diff --git a/dnt/authapp/forms.py b/dnt/authapp/forms.py index d22a5fc..cd71b80 100644 --- a/dnt/authapp/forms.py +++ b/dnt/authapp/forms.py @@ -20,7 +20,7 @@ class AuthUserRegisterForm(UserCreationForm): class Meta: model = AuthUser - fields = ('username', 'birthdate', 'email', 'avatar') + fields = ('username', 'nickname', 'birthdate', 'email', 'avatar') def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -32,7 +32,7 @@ def __init__(self, *args, **kwargs): class AuthUserEditForm(UserChangeForm): class Meta: model = AuthUser - fields = ('username', 'birthdate', 'email', 'avatar', 'password') + fields = ('username', 'nickname', 'birthdate', 'email', 'avatar', 'password') def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) diff --git a/dnt/authapp/migrations/0009_alter_authuser_avatar.py b/dnt/authapp/migrations/0009_alter_authuser_avatar.py new file mode 100644 index 0000000..88e6818 --- /dev/null +++ b/dnt/authapp/migrations/0009_alter_authuser_avatar.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.7 on 2023-04-10 21:38 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('authapp', '0008_authuser_current_lp_authuser_division_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='authuser', + name='avatar', + field=models.ImageField(blank=True, null=True, upload_to='users', verbose_name='Аватар'), + ), + ] diff --git a/dnt/authapp/models.py b/dnt/authapp/models.py index 4c2a32a..0b16b38 100644 --- a/dnt/authapp/models.py +++ b/dnt/authapp/models.py @@ -41,6 +41,10 @@ class AuthUser(AbstractUser): current_game = models.ForeignKey(Game, on_delete=models.SET_NULL, null=True, blank=True) avatar = models.ImageField(upload_to="users", verbose_name=_("Аватар"), **NULLABLE) + @property + def get_friends(self): + return AuthUser.objects.filter(pk__in=self.friends.values_list('pk')) + class QuestionRatedByUser(models.Model): """ @@ -62,3 +66,6 @@ class Remark(models.Model): class Meta: unique_together = ('question', 'author',) + + def __str__(self): + return f'#{self.text} {self.rating}' \ No newline at end of file diff --git a/dnt/authapp/templates/authapp/edit.html b/dnt/authapp/templates/authapp/edit.html index 23cdf4c..a7dab4a 100644 --- a/dnt/authapp/templates/authapp/edit.html +++ b/dnt/authapp/templates/authapp/edit.html @@ -1,14 +1,17 @@ -{% extends 'authapp/base.html' %} -{% load static %} +{% extends 'main/base.html' %} -{% block content %} -
+{% block title %} + Редактировать профиль +{% endblock %} + +{% block body %} + {% csrf_token %} -

Edit

+

Редактировать профиль

{% for field in edit_form %}
{% if field.label != "Password" %} - {{ field.label_tag }}{{ field }}{{ field.errors }} +

{{ field.label_tag }}{{ field }}

{{ field.errors }} {% endif %}
{% endfor %} @@ -17,8 +20,9 @@

Edit

{{ field.label_tag }}{{ field }}{{ field.errors }} {% endfor %} - +
+ +
-Back {% endblock %} diff --git a/dnt/authapp/templates/authapp/login.html b/dnt/authapp/templates/authapp/login.html index 1255036..4f6c240 100644 --- a/dnt/authapp/templates/authapp/login.html +++ b/dnt/authapp/templates/authapp/login.html @@ -11,7 +11,7 @@ {% endif %} {% for field in login_form %} -

{{ field.label_tag }}{{ field }}

{{ field.errors }} +

{{ field.label_tag }}{{ field }}

{% endfor %}
Регистрация diff --git a/dnt/authapp/views.py b/dnt/authapp/views.py index b17e675..74747b0 100644 --- a/dnt/authapp/views.py +++ b/dnt/authapp/views.py @@ -1,7 +1,8 @@ -from django.shortcuts import render, get_object_or_404 +from django.shortcuts import render from django.contrib import auth from django.http import HttpResponseRedirect from django.urls import reverse +from django.contrib.auth.decorators import login_required from authapp.forms import AuthUserRegisterForm, AuthUserLoginForm, AuthUserEditForm @@ -52,6 +53,7 @@ def register(request): return render(request, 'authapp/register.html', context) +@login_required def edit(request): if request.method == 'POST': edit_form = AuthUserEditForm(request.POST, request.FILES, instance=request.user) diff --git a/dnt/chat/__init__.py b/dnt/chat/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/dnt/chat/admin.py b/dnt/chat/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/dnt/chat/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/dnt/chat/apps.py b/dnt/chat/apps.py new file mode 100644 index 0000000..2fe899a --- /dev/null +++ b/dnt/chat/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class ChatConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'chat' diff --git a/dnt/chat/migrations/0001_initial.py b/dnt/chat/migrations/0001_initial.py new file mode 100644 index 0000000..854855e --- /dev/null +++ b/dnt/chat/migrations/0001_initial.py @@ -0,0 +1,48 @@ +# Generated by Django 4.1.7 on 2023-04-10 17:41 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('games', '0006_alter_game_type_alter_lobby_type_alter_queue_type'), + ] + + operations = [ + migrations.CreateModel( + name='LobbyMessage', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('text', models.CharField(max_length=128)), + ('created_at', models.DateTimeField(auto_now=True)), + ('lobby', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='games.lobby')), + ('sender', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='GameMessage', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('text', models.CharField(max_length=128)), + ('created_at', models.DateTimeField(auto_now=True)), + ('game', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='games.game')), + ('sender', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='FriendMessage', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('text', models.CharField(max_length=128)), + ('created_at', models.DateTimeField(auto_now=True)), + ('receiver', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='receiver', to=settings.AUTH_USER_MODEL)), + ('sender', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sender', to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/dnt/chat/migrations/__init__.py b/dnt/chat/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/dnt/chat/models.py b/dnt/chat/models.py new file mode 100644 index 0000000..37663f2 --- /dev/null +++ b/dnt/chat/models.py @@ -0,0 +1,25 @@ +from django.db import models +from authapp.models import AuthUser +from games.models import Game, Lobby + +class FriendMessage(models.Model): + + sender = models.ForeignKey(AuthUser, on_delete=models.CASCADE, related_name='sender') + receiver = models.ForeignKey(AuthUser, on_delete=models.CASCADE, related_name='receiver') + text = models.CharField(max_length=128) + created_at = models.DateTimeField(auto_now=True) + +class LobbyMessage(models.Model): + + sender = models.ForeignKey(AuthUser, on_delete=models.CASCADE) + lobby = models.ForeignKey(Lobby, on_delete=models.CASCADE) + text = models.CharField(max_length=128) + created_at = models.DateTimeField(auto_now=True) + +class GameMessage(models.Model): + + sender = models.ForeignKey(AuthUser, on_delete=models.CASCADE) + game = models.ForeignKey(Game, on_delete=models.CASCADE) + text = models.CharField(max_length=128) + created_at = models.DateTimeField(auto_now=True) + diff --git a/dnt/chat/tests.py b/dnt/chat/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/dnt/chat/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/dnt/chat/urls.py b/dnt/chat/urls.py new file mode 100644 index 0000000..cc62a8e --- /dev/null +++ b/dnt/chat/urls.py @@ -0,0 +1,9 @@ +from django.urls import path +import chat.views as chat + +app_name = 'chat' + +urlpatterns = [ + path('load_messages/', chat.load_messages, name='load_messages'), + path('create_messages/', chat.create_messages, name='create_messages'), +] diff --git a/dnt/chat/views.py b/dnt/chat/views.py new file mode 100644 index 0000000..3fc5a4c --- /dev/null +++ b/dnt/chat/views.py @@ -0,0 +1,62 @@ +from django.shortcuts import render +from django.core import serializers +from django.http import JsonResponse +from chat.models import GameMessage, FriendMessage, LobbyMessage +from django.db.models import Q +from authapp.models import AuthUser +from channels.layers import get_channel_layer +from asgiref.sync import async_to_sync +import json +from games.models import Lobby, Game + + +def load_messages(request): + type_ = request.GET.get('type') + if type_ == 'friend': + friend_pk = int(request.GET.get('friend_pk')) + friend = AuthUser.objects.get(pk=friend_pk) + messages = FriendMessage.objects.filter(Q(sender__in=[request.user, friend]) + & Q(receiver__in=[request.user, friend])).order_by('-created_at') + return JsonResponse({'messages': list(messages.values()), 'friend_nickname': friend.nickname, 'user_nickname': request.user.nickname}, safe=False) + elif type_ == 'lobby': + lobby = request.user.current_lobby + messages = LobbyMessage.objects.filter(lobby=lobby).order_by('-created_at') + players = lobby.players.all() + return JsonResponse({'messages': list(messages.values()), 'players': {player.pk: player.nickname for player in players}}, safe=False) + elif type_ == 'game': + game = request.user.current_game + messages = GameMessage.objects.filter(game=game).order_by('-created_at') + players = AuthUser.objects.filter(pk__in=game.players) + return JsonResponse( + {'messages': list(messages.values()), 'players': {player.pk: player.nickname for player in players}}, + safe=False) + + +def create_messages(request): + type_ = request.GET.get('type') + if type_ == 'friend': + button_message = request.GET.get('message') + receiver_pk = int(request.GET.get('receiver')) + sender_pk = int(request.GET.get('sender')) + msg = FriendMessage.objects.create(text=button_message, receiver_id=receiver_pk, sender_id=sender_pk) + data = {'action': 'chat_message', 'message': serializers.serialize('json', [msg]), 'sender': request.user.nickname, 'type': 'friend'} + layer = get_channel_layer() + for pk in [sender_pk, receiver_pk]: + async_to_sync(layer.group_send)(f'user_{pk}', {'type': 'send_message', 'message': data}) + elif type_ == 'lobby': + button_message = request.GET.get('message') + lobby = request.user.current_lobby + msg = LobbyMessage.objects.create(text=button_message, lobby_id=lobby.pk, sender_id=request.user.pk) + data = {'action': 'chat_message', 'message': serializers.serialize('json', [msg]), 'sender': request.user.nickname, 'type': 'lobby'} + layer = get_channel_layer() + for player in lobby.players.all(): + async_to_sync(layer.group_send)(f'user_{player.pk}', {'type': 'send_message', 'message': data}) + elif type_ == 'game': + button_message = request.GET.get('message') + game = request.user.current_game.pk + msg = GameMessage.objects.create(text=button_message, game_id=game, sender_id=request.user.pk) + data = {'action': 'chat_message', 'message': serializers.serialize('json', [msg]), 'sender': request.user.nickname} + layer = get_channel_layer() + async_to_sync(layer.group_send)(f'game_{request.user.current_game.pk}', {'type': 'send_message', 'message': data}) + + return JsonResponse({'ok': 'ok'}) diff --git a/dnt/dnt/asgi.py b/dnt/dnt/asgi.py index 0bc79d6..7f64f91 100644 --- a/dnt/dnt/asgi.py +++ b/dnt/dnt/asgi.py @@ -8,13 +8,13 @@ django_asgi_app = get_asgi_application() from channels.auth import AuthMiddlewareStack -import games.routing +import games.routing#, chat.routing application = ProtocolTypeRouter({ 'http': django_asgi_app, 'websocket': AuthMiddlewareStack( URLRouter( - games.routing.websocket_urlpatterns + games.routing.websocket_urlpatterns #+ chat.routing.websocket_urlpatterns ) ) }) diff --git a/dnt/dnt/settings.py b/dnt/dnt/settings.py index 85ffa83..d73d271 100644 --- a/dnt/dnt/settings.py +++ b/dnt/dnt/settings.py @@ -41,6 +41,7 @@ 'channels', + 'chat', 'custom_admin', 'authapp', 'games', @@ -74,6 +75,7 @@ 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', + 'django.template.context_processors.media' ], }, }, @@ -147,6 +149,7 @@ MEDIA_URL = '/media/' MEDIA_ROOT = BASE_DIR / 'media' +DEFAULT_AVATAR_URL = '/users/' # Default primary key field type diff --git a/dnt/dnt/urls.py b/dnt/dnt/urls.py index d36b3df..85155ce 100644 --- a/dnt/dnt/urls.py +++ b/dnt/dnt/urls.py @@ -10,6 +10,7 @@ path('', main.index, name='home'), # todo # path('index/', main.index, name="home"), path('authapp/', include('authapp.urls', namespace='auth')), + path('chat/', include('chat.urls', namespace='chat')), path('custom_admin/', include('custom_admin.urls', namespace='custom_admin')), path('games/', include('games.urls', namespace='games')), path('quest/', include('questions.urls', namespace='quest')), diff --git a/dnt/games/models.py b/dnt/games/models.py index ea36748..fdb8a7f 100644 --- a/dnt/games/models.py +++ b/dnt/games/models.py @@ -3,9 +3,7 @@ TYPES = ( ('normal', 'Обычная'), - ('ranked', 'Ранговая'), - ('theme', 'Тематическая'), - ('friend', 'Дружеская') + ('theme', 'Тематическая') ) @@ -75,4 +73,13 @@ class Game(models.Model): @property def players(self): - return list(self.results.keys()) \ No newline at end of file + return list(self.results.keys()) + + @property + def display_type(self): + return eval(self.type)[1] + + @property + def get_time(self): + return self.started.strftime("%Y-%m-%d/%H:%M") + diff --git a/dnt/games/routing.py b/dnt/games/routing.py index 6a4bda1..d9033da 100644 --- a/dnt/games/routing.py +++ b/dnt/games/routing.py @@ -4,5 +4,6 @@ websocket_urlpatterns = [ path('ws/user/', consumers.GamesConsumer.as_asgi()), path('ws/queue/', consumers.GamesConsumer.as_asgi()), - path('ws/game/', consumers.GamesConsumer.as_asgi()) + path('ws/game/', consumers.GamesConsumer.as_asgi()), + #path('ws/chat/', consumers.ChatConsumers.as_asgi() ] diff --git a/dnt/games/templates/games/game.html b/dnt/games/templates/games/game.html index 74173ee..bb3e667 100644 --- a/dnt/games/templates/games/game.html +++ b/dnt/games/templates/games/game.html @@ -1,36 +1,50 @@ +{% extends "main/base.html" %} {% load static %} - - - - - Title - +{% block title %}Игровое лобби{% endblock %} +{% block style %} + +{% endblock %} +{% block js_second %} - - -

{{ request.user.current_game.pk }}

-{% if themes %} -
-{% for theme in themes %} - {{ theme.0 }} -{% endfor %} -
-{% endif %} - - -
-

-
- -
-
- {% for user in users %} -
- {{ user.nickname }} - -
+{% endblock %} +{% block body %} +
+ {% if themes %} +
+ Играются следующие темы: + {% for theme in themes %} + {{ theme.0 }} {% endfor %} +
+ {% endif %} + + +
+

+
+ +
+
+ + {% for user in users %} + + + + + {% endfor %} +
{{ user.nickname }} 0
+
+
+Открыть игровой чат +
+
+ Игровой чат + Х +
+
+ +
+
- - \ No newline at end of file +{% endblock %} \ No newline at end of file diff --git a/dnt/games/templates/games/lobby.html b/dnt/games/templates/games/lobby.html index cdbfdd8..c094fc3 100644 --- a/dnt/games/templates/games/lobby.html +++ b/dnt/games/templates/games/lobby.html @@ -1,11 +1,11 @@ +{% extends "main/base.html" %} {% load static %} - - - - - Title - +{% block title %}Игровое лобби{% endblock %} +{% block style %} + +{% endblock %} +{% block js_first %} - +{% endblock %} +{% block js_second %} - - - - - - -Начать игру -: -
-

{{ user.nickname }}

- {% if users %} - {% for u in users %} -

{{ u.nickname }}

- {% endfor %} - {% endif %} -
-

{{ user.current_lobby.pk }}

- -

Пригласить друга

-
- {% for friend in friends %} - {{ friend.nickname }} - {% endfor %} -
-{% if theme %} - -{% endif %} - - \ No newline at end of file +{% endblock %} +{% block body %} +
+
+ Режим игры: + + {% if theme %} + Выберите тему для игры: + + {% endif %} +
+ +
+ {% for b in blanks_left %} +
+ {% endfor %} + {% for u in users_left %} +
{{ u.nickname }}
+ {% endfor %} +
+ {{ user.nickname }} +
+ {% for u in users_right %} +
{{ u.nickname }}
+ {% endfor %} + {% for b in blanks_right %} +
+ {% endfor %} +
+
+
+ Начать игру +
+ : +
+
+
+
+ Открыть чат лобби +
+
+ Чат лобби + Х +
+
+ +
+ +
+{% endblock %} \ No newline at end of file diff --git a/dnt/games/templates/games/results.html b/dnt/games/templates/games/results.html index 6740f91..fc87f31 100644 --- a/dnt/games/templates/games/results.html +++ b/dnt/games/templates/games/results.html @@ -1,16 +1,21 @@ - - - - - Title - - -{% for result in results %} -
- {{ result.1 }} - {{ result.0.nickname }} - {{ result.2 }} -
-{% endfor %} - - \ No newline at end of file +{% extends "main/base.html" %} +{% load static %} + +{% block title %}Игровое лобби{% endblock %} +{% block style %} + +{% endblock %} +{% block body %} +
+ + {% for result in results %} + + + + + + {% endfor %} +
{{ result.1 }} {{ result.0.nickname }} {{ result.2 }}
+ +
+{% endblock %} \ No newline at end of file diff --git a/dnt/games/urls.py b/dnt/games/urls.py index 506e578..0ed2b7f 100644 --- a/dnt/games/urls.py +++ b/dnt/games/urls.py @@ -6,6 +6,7 @@ urlpatterns = [ path('lobby/', games.create_lobby, name='lobby'), path('join_lobby/', games.join_lobby, name='join_lobby'), + path('join_lobby_ajax/', games.join_lobby_ajax, name='join_lobby_ajax'), path('change_game_mode/', games.change_game_mode, name='change_game_mode'), path('queue/', games.queue, name='queue'), path('quit_lobby/', games.quit_lobby, name='quit_lobby'), diff --git a/dnt/games/views.py b/dnt/games/views.py index 16d688f..0e7dffe 100644 --- a/dnt/games/views.py +++ b/dnt/games/views.py @@ -16,9 +16,11 @@ from channels.layers import get_channel_layer from asgiref.sync import async_to_sync from variables import * +from django.contrib.auth.decorators import login_required # view страницы игрового лобби и очереди и создания игрового лобби +@login_required def create_lobby(request): # создание лобби и добавление его в объект пользователя в качестве current_lobby @@ -33,13 +35,16 @@ def create_lobby(request): 'user': current_user, 'modes': Game.types, 'max_players': GAME_MAX_PLAYERS, - 'users': '', - 'friends': AuthUser.objects.filter(pk__in=current_user.friends.values_list('pk')) + 'users_left': [], + 'users_right': [], + 'blanks_left': range(math.floor((GAME_MAX_PLAYERS - 1) / 2)), + 'blanks_right': range(math.ceil((GAME_MAX_PLAYERS - 1) / 2)), } + return render(request, 'games/lobby.html', context=context) -def join_lobby(request): +def join_lobby_ajax(request): sender = AuthUser.objects.get(pk=int(request.GET.get('sender_id'))) lobby = Lobby.objects.get(pk=sender.current_lobby.pk) @@ -49,7 +54,7 @@ def join_lobby(request): current_user.current_lobby = lobby current_user.is_lobby_leader = False current_user.save() - friends = [x[0] for x in current_user.friends.values_list('pk') if x not in [player.pk for player in lobby.players.all()]] + # friends = [x[0] for x in current_user.friends.values_list('pk') if x not in [player.pk for player in lobby.players.all()]] last_place = True if current_user.current_lobby.players_count == GAME_MAX_PLAYERS else False data = {'action': 'player_join', 'joiner_pk': current_user.pk, 'joiner_nickname': current_user.nickname, @@ -58,22 +63,36 @@ def join_lobby(request): for user in AuthUser.objects.filter(current_lobby=current_user.current_lobby).exclude(pk=current_user.pk): async_to_sync(layer.group_send)(f'user_{user.pk}', {'type': 'send_message', 'message': data}) - theme = True if eval(lobby.type)[0] == 'theme' else False + return JsonResponse({'status': 'ok', 'url': 'http://' + request.META['HTTP_HOST'] + '/games/join_lobby/'}) + else: + return JsonResponse({'status': 'full'}) + - context = { - 'title': 'Игровое лобби', - 'user': current_user, - 'modes': Game.types, - 'max_players': GAME_MAX_PLAYERS, - 'users': AuthUser.objects.filter(current_lobby=lobby).exclude(pk=current_user.pk), - 'friends': friends, - 'theme': theme, - 'themes': Category.objects.all().values_list('name') - } +@login_required +def join_lobby(request): - return HttpResponse(render_to_string('games/lobby.html', context=context)) - else: - return HttpResponse('full') + current_user = request.user + current_lobby = current_user.current_lobby + + theme = True if eval(current_lobby.type)[0] == 'theme' else False + + users_left = [j for i, j in enumerate(AuthUser.objects.filter(current_lobby=current_lobby).exclude(pk=current_user.pk)) if (i + 1) % 2 == 0] + users_right = [j for i, j in enumerate(AuthUser.objects.filter(current_lobby=current_lobby).exclude(pk=current_user.pk)) if (i + 1) % 2 == 1] + + context = { + 'title': 'Игровое лобби', + 'user': current_user, + 'modes': Game.types, + 'max_players': GAME_MAX_PLAYERS, + 'users_left': users_left, + 'users_right': users_right, + 'blanks_left': range(math.floor((GAME_MAX_PLAYERS - 1) / 2) - len(users_left)), + 'blanks_right': range(math.ceil((GAME_MAX_PLAYERS - 1) / 2) - len(users_right)), + 'theme': theme, + 'themes': Category.objects.all().values_list('name') + } + + return render(request, 'games/lobby.html', context=context) def change_game_mode(request): @@ -175,7 +194,7 @@ def quit_lobby(request): current_user = request.user # если пользователь в лобби один, лобби удаляется, если нет - лобби убирается из current_lobby объекта пользователя - if current_user.current_lobby and current_user.current_lobby.players_count == 1: + if current_user.current_lobby is not None and current_user.current_lobby.players_count == 1: current_user.current_lobby.delete() elif current_user.current_lobby is not None: data = {'action': 'player_quit', 'quitter_pk': current_user.pk, 'quitter_nickname': current_user.nickname, @@ -219,6 +238,7 @@ def cancel_queue(request): # view страницы игры +@login_required def game(request): context = { @@ -247,7 +267,7 @@ def start_game(request): for _ in range(questions_count): # получение случайного вопроса, которого не было в игре, и добавление его в объект игры в current_question - questions = Question.objects.exclude(pk__in=current_game.asked_questions.values_list('pk')) + questions = Question.objects.exclude(pk__in=current_game.asked_questions.values_list('pk')).filter(is_validated=True) current_game = Game.objects.get(pk=request.user.current_game.pk) if eval(current_game.type)[0] in ['theme', 'friend']: questions = questions.filter(category__pk__in=current_game.categories.values_list('pk')) @@ -260,7 +280,7 @@ def start_game(request): # попытка получить нужное количество неправильных ответов того же подтипа, что и верный first_answers = Answer.objects.filter( - Q(subtype=question.answer.subtype) & ~Q(pk=question.answer.pk) + Q(subtype=question.answer.subtype) & ~Q(pk=question.answer.pk) & Q(is_validated=True) ).order_by('?')[:GAME_SUBTYPE_ANSWERS_COUNT] # компенсация возможного недостатка неправильных ответов того же подтипа неправильными ответами того же типа @@ -268,10 +288,10 @@ def start_game(request): type_answers_count += GAME_SUBTYPE_ANSWERS_COUNT - len(first_answers) # получение необходимого количества неправильных ответов того же типа - type_answers = Answer.objects.exclude(subtype=question.answer.subtype).order_by('?')[:type_answers_count] + type_answers = Answer.objects.filter(is_validated=True).exclude(subtype=question.answer.subtype).order_by('?')[:type_answers_count] # преобразование всех нужных ответов в список словарей и перемешивание их - answers = first_answers | Answer.objects.filter(pk=question.answer.pk) | type_answers + answers = first_answers | Answer.objects.filter(pk=question.answer.pk, is_validated=True) | type_answers answers = list(answers.values()) random.shuffle(answers) @@ -399,6 +419,7 @@ def check_answer(request): # view страницы результатов игры +@login_required def results(request, game_id): # получение объекта нужной игры и всех её игроков diff --git a/dnt/json/answers.json b/dnt/json/answers.json index 54ebcfd..fa581ba 100644 --- a/dnt/json/answers.json +++ b/dnt/json/answers.json @@ -1,70 +1,87 @@ [ { "answer": "Губка Боб Квадратные Штаны", - "subtype": "Персонаж мультфильма" + "subtype": "Персонаж мультфильма", + "is_validated": true }, { "answer": "Анна Франк", - "subtype": "Историческая личность" + "subtype": "Историческая личность", + "is_validated": true }, { "answer": "Джон Мильтон", - "subtype": "Поэт" + "subtype": "Поэт", + "is_validated": true }, { "answer": "Император Хирохито", - "subtype": "Политический деятель" + "subtype": "Политический деятель", + "is_validated": true }, { "answer": "Харрисон Форд", - "subtype": "Актёр" + "subtype": "Актёр", + "is_validated": true }, { "answer": "Хэлли Берри", - "subtype": "Актриса" + "subtype": "Актриса", + "is_validated": true }, { "answer": "Мухаммед Али", - "subtype": "Боксёр" + "subtype": "Боксёр", + "is_validated": true }, { "answer": "Харпер Ли", - "subtype": "Писательница" + "subtype": "Писательница", + "is_validated": true }, { "answer": "Галилео Галилей", - "subtype": "Учёный" + "subtype": "Учёный", + "is_validated": true }, { "answer": "Мари Кюри", - "subtype": "Учёная" + "subtype": "Учёная", + "is_validated": true }, { "answer": "Нил Армстронг", - "subtype": "Космонавт" + "subtype": "Космонавт", + "is_validated": true }, { "answer": "Рианна", - "subtype": "Певица" + "subtype": "Певица", + "is_validated": true }, { "answer": "Куинси Джонс", - "subtype": "Продюсер" + "subtype": "Продюсер", + "is_validated": true }, { "answer": "Джордж Р. Р. Мартин", - "subtype": "Писатель" + "subtype": "Писатель", + "is_validated": true }, { "answer": "Гена", - "subtype": "Персонаж мультфильма" + "subtype": "Персонаж мультфильма", + "is_validated": true }, { "answer": "Кот Матроскин", - "subtype": "Персонаж мультфильма" + "subtype": "Персонаж мультфильма", + "is_validated": true }, { "answer": "Джон Сноу", - "subtype": "Персонаж телесериала" + "subtype": "Персонаж телесериала", + "is_validated": true } ] \ No newline at end of file diff --git a/dnt/main/management/commands/fill.py b/dnt/main/management/commands/fill.py index fa456fd..84941a1 100644 --- a/dnt/main/management/commands/fill.py +++ b/dnt/main/management/commands/fill.py @@ -43,18 +43,12 @@ def handle(self, *args, **options): question['answer'] = Answer.objects.get(answer=question['answer']) Question.objects.create(**question) - try: - AuthUser.objects.get(username='pepper').delete() - except: - pass + AuthUser.objects.all().delete() + AuthUser.objects.create_superuser(username='pepper', password='pepper123', nickname='pepper', birthdate='2019-01-01', is_moderator=True) for i in range(2, 10): - try: - AuthUser.objects.get(username=f'pepper{i}').delete() - except: - pass AuthUser.objects.create_superuser(username=f'pepper{i}', password='pepper123', nickname=f'pepper{i}', birthdate='2019-01-01') diff --git a/dnt/main/templates/main/base.html b/dnt/main/templates/main/base.html index fb90254..a87ba3c 100644 --- a/dnt/main/templates/main/base.html +++ b/dnt/main/templates/main/base.html @@ -7,17 +7,18 @@ {% block title %}{% endblock %} {% block style %}{% endblock %} - {% block js %}{% endblock %} + + + {% block js_first %}{% endblock %} + + {% block js_second %}{% endblock %} {% block header %} {% include "main/includes/header.html" %} {% endblock %} -
- - Принять - Отклонить -
{% block body %}{% endblock %}
@@ -26,5 +27,15 @@ {% include "main/includes/footer.html" %} {% endblock %} +
+
+ + Х +
+
+ +
+ +
\ No newline at end of file diff --git a/dnt/main/templates/main/includes/header.html b/dnt/main/templates/main/includes/header.html index 231cebd..2489879 100644 --- a/dnt/main/templates/main/includes/header.html +++ b/dnt/main/templates/main/includes/header.html @@ -1,3 +1,5 @@ +{% load static %} +
-
- {% if not request.user.is_authenticated %} - Войти - Зарегистрироваться - {% else %} - Выйти - Просмотр профиля - Редактировать профиль - {% endif %} - {% if request.user.is_authenticated and request.user.current_game %} - Продолжить игру - {% elif request.user.is_authenticated %} - Играть - {% endif %} - {% if request.user.is_moderator %} - Модерация вопросов - Добавить вопрос - {% elif request.user.is_authenticated %} - Оценка вопросов - Предложить вопрос - {% endif %} -
+
+ {% if request.resolver_match.url_name != 'game' %} +
+ + Принять + Отклонить +
+ {% if not request.user.is_authenticated %} + Войти + Зарегистрироваться + {% else %} + Выйти + Просмотр профиля + {% endif %} + {% if request.user.is_authenticated and request.user.current_game %} + Продолжить игру + {% elif request.user.is_authenticated %} + Играть +
+ Друзья +
+ Добавить друга + {% for friend in request.user.get_friends %} +
{{ friend.nickname }} +
chat + invite
+
+ {% endfor %} +
+
+ {% endif %} + {% if request.user.is_moderator %} + Модерация вопросов + Добавить вопрос + {% elif request.user.is_authenticated %} + Оценка вопросов + Предложить вопрос + {% endif %} + {% else %} + Приятной игры! + {% endif %} +
\ No newline at end of file diff --git a/dnt/media/users/ava.jpg b/dnt/media/users/ava.jpg new file mode 100644 index 0000000..93fe28a Binary files /dev/null and b/dnt/media/users/ava.jpg differ diff --git a/dnt/media/users/avatar_rMO7Sgc.jpg b/dnt/media/users/avatar_rMO7Sgc.jpg new file mode 100644 index 0000000..22fe548 Binary files /dev/null and b/dnt/media/users/avatar_rMO7Sgc.jpg differ diff --git a/dnt/media/users/doom.jpg b/dnt/media/users/doom.jpg new file mode 100644 index 0000000..928e25f Binary files /dev/null and b/dnt/media/users/doom.jpg differ diff --git a/dnt/media/users/if-union-pay-2593673_86618.png b/dnt/media/users/if-union-pay-2593673_86618.png deleted file mode 100644 index 0f6777e..0000000 Binary files a/dnt/media/users/if-union-pay-2593673_86618.png and /dev/null differ diff --git a/dnt/media/users/user.png b/dnt/media/users/user002.png similarity index 100% rename from dnt/media/users/user.png rename to dnt/media/users/user002.png diff --git a/dnt/media/users/user_7fBqBIR.png b/dnt/media/users/user_7fBqBIR.png deleted file mode 100644 index 228c3f9..0000000 Binary files a/dnt/media/users/user_7fBqBIR.png and /dev/null differ diff --git a/dnt/media/users/user_8GAE07v.png b/dnt/media/users/user_8GAE07v.png deleted file mode 100644 index 228c3f9..0000000 Binary files a/dnt/media/users/user_8GAE07v.png and /dev/null differ diff --git a/dnt/media/users/user_Nj1oBxZ.png b/dnt/media/users/user_Nj1oBxZ.png deleted file mode 100644 index 228c3f9..0000000 Binary files a/dnt/media/users/user_Nj1oBxZ.png and /dev/null differ diff --git a/dnt/media/users/user_YpxxOby.png b/dnt/media/users/user_YpxxOby.png deleted file mode 100644 index 228c3f9..0000000 Binary files a/dnt/media/users/user_YpxxOby.png and /dev/null differ diff --git a/dnt/media/users/user_vtbvLzD.png b/dnt/media/users/user_vtbvLzD.png deleted file mode 100644 index 228c3f9..0000000 Binary files a/dnt/media/users/user_vtbvLzD.png and /dev/null differ diff --git a/dnt/questions/migrations/0005_alter_category_options_alter_subtype_options_and_more.py b/dnt/questions/migrations/0005_alter_category_options_alter_subtype_options_and_more.py new file mode 100644 index 0000000..38398aa --- /dev/null +++ b/dnt/questions/migrations/0005_alter_category_options_alter_subtype_options_and_more.py @@ -0,0 +1,29 @@ +# <<<<<<< HEAD +# Generated by Django 4.1.7 on 2023-04-10 17:41 +# ======= +# Generated by Django 4.1.7 on 2023-04-10 21:38 +# >>>>>>> origin/main + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('questions', '0004_alter_question_options'), + ] + + operations = [ + migrations.AlterModelOptions( + name='category', + options={'ordering': ('name',)}, + ), + migrations.AlterModelOptions( + name='subtype', + options={'ordering': ('name',)}, + ), + migrations.AlterModelOptions( + name='type', + options={'ordering': ('name',)}, + ), + ] diff --git a/dnt/questions/migrations/0006_answer_is_validated.py b/dnt/questions/migrations/0006_answer_is_validated.py new file mode 100644 index 0000000..d9c858f --- /dev/null +++ b/dnt/questions/migrations/0006_answer_is_validated.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.7 on 2023-04-23 13:04 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('questions', '0005_alter_category_options_alter_subtype_options_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='answer', + name='is_validated', + field=models.BooleanField(default=False), + ), + ] diff --git a/dnt/questions/models.py b/dnt/questions/models.py index 6482cf8..71298c0 100644 --- a/dnt/questions/models.py +++ b/dnt/questions/models.py @@ -8,7 +8,7 @@ class Meta: ordering = ('name',) def __str__(self): - return f'#{self.name}' + return f'{self.name}' class Type(models.Model): @@ -16,8 +16,9 @@ class Type(models.Model): class Meta: ordering = ('name',) + def __str__(self): - return f'#{self.name}' + return f'{self.name}' class SubType(models.Model): @@ -28,15 +29,16 @@ class Meta: ordering = ('name',) def __str__(self): - return f'#{self.name}' + return f'{self.name}' class Answer(models.Model): answer = models.CharField(max_length=64, verbose_name='Ответ') subtype = models.ForeignKey(SubType, on_delete=models.CASCADE, verbose_name='Подтип') + is_validated = models.BooleanField(default=False) def __str__(self): - return f'#{self.answer}' + return f'{self.answer}' class Question(models.Model): @@ -51,7 +53,7 @@ class Meta: ordering = ('-created_at',) def __str__(self): - return f'#{self.question}' + return f'{self.question}' class QuestionComplaint(models.Model): @@ -59,4 +61,4 @@ class QuestionComplaint(models.Model): text = models.CharField(max_length=128, verbose_name='Жалоба') def __str__(self): - return f'#{self.text}' \ No newline at end of file + return f'{self.text}' diff --git a/dnt/questions/templates/questions/add_quest.html b/dnt/questions/templates/questions/add_quest.html index 0467fb4..13daf72 100644 --- a/dnt/questions/templates/questions/add_quest.html +++ b/dnt/questions/templates/questions/add_quest.html @@ -1,10 +1,10 @@ - - - - - Добавление вопроса - - +{% extends "main/base.html" %} +{% load static %} +{% block title %} + Добавить вопрос +{% endblock %} + +{% block body %} {% include 'questions/includes/messages.html' %}

Добавить вопрос

@@ -45,17 +45,16 @@

Добавить вопрос

-{% block js %} - -{% endblock %} - - \ No newline at end of file + + {% endblock %} +{% endblock %} \ No newline at end of file diff --git a/dnt/questions/templates/questions/grade_quest.html b/dnt/questions/templates/questions/grade_quest.html index e456186..043df8f 100644 --- a/dnt/questions/templates/questions/grade_quest.html +++ b/dnt/questions/templates/questions/grade_quest.html @@ -1,55 +1,62 @@ - - - - - Title - - -{% include 'questions/includes/messages.html' %} -

Оценить вопрос

-
- {% csrf_token %} -

- -

-

- -

-

- -

-

- -

-

- -

-
+{% extends "main/base.html" %} +{% load static %} +{% block title %} + Оценка вопросов +{% endblock %} -{% block js %} - -{% endblock %} - - \ No newline at end of file + + {% endblock %} +{% endblock %} \ No newline at end of file diff --git a/dnt/questions/templates/questions/includes/messages.html b/dnt/questions/templates/questions/includes/messages.html index ab38d9a..ab0108c 100644 --- a/dnt/questions/templates/questions/includes/messages.html +++ b/dnt/questions/templates/questions/includes/messages.html @@ -10,16 +10,6 @@ {% endif %} " role="alert" aria-live="assertive" aria-atomic="true" style="right: 0;"> -
- - - {{ message.tags|capfirst }} message - just now - -
{{ message }}
diff --git a/dnt/questions/templates/questions/offer_quest.html b/dnt/questions/templates/questions/offer_quest.html index 147d41e..0c7155c 100644 --- a/dnt/questions/templates/questions/offer_quest.html +++ b/dnt/questions/templates/questions/offer_quest.html @@ -1,65 +1,67 @@ - - - - - Предложение вопроса - - -{% include 'questions/includes/messages.html' %} -

Предложить вопрос

-
- {% csrf_token %} -

- -

-

- -

-

- -

-

- -

-

- -

-

- -

-
-{% block js %} - -{% endblock %} - - \ No newline at end of file + + + {% endblock %} +{% endblock %} \ No newline at end of file diff --git a/dnt/questions/templates/questions/qes_list.html b/dnt/questions/templates/questions/qes_list.html index 3bb3e5c..7060d99 100644 --- a/dnt/questions/templates/questions/qes_list.html +++ b/dnt/questions/templates/questions/qes_list.html @@ -1,36 +1,23 @@ - - - - - Модерация вопросов - - -

Модерация вопросов

-{% for item in object_list %} -{% if item.is_validated == False %} -
-

{{ item.category.name }}

-

{{ item.created_at }}

-

{{ item.question }}

-

{{ item.answer }}

- Одобрить - Не одобрять -
- {% csrf_token %} - -

- -

-

- -

-
-
-{% endif %} -{% endfor %} - - \ No newline at end of file +{% extends "main/base.html" %} +{% load static %} +{% block title %} + Модерация вопросов +{% endblock %} + +{% block body %} +

Модерация вопросов

+ {% for item in object_list %} + {% if item.is_validated == False %} +
+

Категория вопроса: {{ item.category.name }}

+

{{ item.created_at }}

+

Вопрос: {{ item.question }}

+

Ответ: {{ item.answer }}

+

Тип: {{ item.answer.subtype.type }}

+

Подтип: {{ item.answer.subtype }}

+ Одобрить + Не одобрять +
+ {% endif %} + {% endfor %} +{% endblock %} \ No newline at end of file diff --git a/dnt/questions/templates/questions/question_confirm_delete.html b/dnt/questions/templates/questions/question_confirm_delete.html index 104eae3..c1edddf 100644 --- a/dnt/questions/templates/questions/question_confirm_delete.html +++ b/dnt/questions/templates/questions/question_confirm_delete.html @@ -1,37 +1,35 @@ - - - - - Title - - -
-
-

Удалить вопрос?

-

- Удалить вопрос:
- "{{ object.question }}" от {{ object.created_at }} -

-

-

-
+{% extends "main/base.html" %} +{% load static %} +{% block title %} + Удалить вопрос +{% endblock %} -
- {% csrf_token %} - -
-
-
- Отмена +{% block body %} +
+
+

Удалить вопрос?

+

+ Удалить вопрос:
+ "{{ object.question }}" от {{ object.created_at }} +

+

+

+
+ +
+ {% csrf_token %} + +
+
+
+

-

-
- - - \ No newline at end of file +{% endblock %} \ No newline at end of file diff --git a/dnt/questions/templates/questions/question_form.html b/dnt/questions/templates/questions/question_form.html index 220958e..313b938 100644 --- a/dnt/questions/templates/questions/question_form.html +++ b/dnt/questions/templates/questions/question_form.html @@ -1,10 +1,10 @@ - - - - - Title - - +{% extends "main/base.html" %} +{% load static %} +{% block title %} + Подтверждение добавления +{% endblock %} + +{% block body %}
@@ -14,5 +14,4 @@
- - \ No newline at end of file +{% endblock %} \ No newline at end of file diff --git a/dnt/questions/views.py b/dnt/questions/views.py index bc1b80b..3874fc2 100644 --- a/dnt/questions/views.py +++ b/dnt/questions/views.py @@ -1,13 +1,16 @@ from django.contrib import messages from django.core.cache import cache +from django.db.models import Q, Sum from django.http import HttpResponseRedirect from django.shortcuts import render, get_object_or_404 from django.urls import reverse, reverse_lazy from django.views.generic import TemplateView, DeleteView, UpdateView, CreateView, DetailView -from authapp.models import Remark, AuthUser +from authapp.models import Remark, AuthUser, QuestionRatedByUser from questions.models import Question, Category, Type, SubType, Answer, QuestionComplaint +from variables import * + class QuestionView(TemplateView): template_name = 'questions/qes_list.html' @@ -105,12 +108,15 @@ def post(self, request, *args, **kwargs): ) return HttpResponseRedirect(reverse('quest:add_quest')) + class GradeQuestionView(TemplateView): template_name = 'questions/grade_quest.html' def get_context_data(self, **kwargs): context_data = super().get_context_data(**kwargs) - context_data['question_list'] = Question.objects.all() + context_data['question_list'] = Question.objects.filter(~Q(pk__in=[x.question.pk for x in Remark.objects.filter(author=self.request.user)]) & + Q(is_validated=False)).order_by('?').first() + context_data['remark_list'] = Remark.objects.filter(question=context_data['question_list']) return context_data def post(self, request, *args, **kwargs): @@ -130,6 +136,15 @@ def post(self, request, *args, **kwargs): rating=request.POST.get('rating'), ) new_remark.save() + question = Question.objects.get(question=request.POST.get('question')) + remark = Remark.objects.filter(question=question).aggregate(Sum('rating')) + if remark['rating__sum'] >= VOTES: + question.is_validated = True + question.save() + question.answer.is_validated = True + question.answer.save() + elif remark['rating__sum'] <= -VOTES: + question.delete() messages.add_message(request, messages.INFO, 'Оценка выполнена') return HttpResponseRedirect(reverse('quest:grade_quest')) else: @@ -145,6 +160,7 @@ def post(self, request, *args, **kwargs): ) return HttpResponseRedirect(reverse('quest:grade_quest')) + class OfferQuestionView(TemplateView): template_name = 'questions/offer_quest.html' diff --git a/dnt/requirements.txt b/dnt/requirements.txt index 3f41acd..68a5c0a 100644 --- a/dnt/requirements.txt +++ b/dnt/requirements.txt @@ -6,7 +6,6 @@ autobahn==23.1.2 Automat==22.10.0 certifi==2022.12.7 cffi==1.15.1 -channels==3.0.1 channels-redis==2.4.2 charset-normalizer==3.1.0 constantly==15.1.0 diff --git a/dnt/requirements_1.txt b/dnt/requirements_1.txt index ae209bd..a6f31f2 100644 --- a/dnt/requirements_1.txt +++ b/dnt/requirements_1.txt @@ -7,3 +7,4 @@ rsa==4.9 sqlparse==0.4.3 Telethon==1.27.0 tzdata==2022.7 + diff --git a/dnt/static/css/games_style.css b/dnt/static/css/games_style.css new file mode 100644 index 0000000..9adde69 --- /dev/null +++ b/dnt/static/css/games_style.css @@ -0,0 +1,342 @@ +#site_content { + padding: 0 10px; + width: 877px; +} + +.lobby_content { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + width: 100%; + height: calc(100vh - 302px); + position: relative; +} + +.lobby_mode { + position: absolute; + left: 5px; + top: 5px; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + z-index: 1; +} + +.lobby_mode > span { + margin-right: 5px; +} + +.lobby_mode > select { + margin-right: 10px; + border: 1px solid #F79F00; + background-color: white; +} + +.lobby_invitation_rejected { + position: absolute; + top: 5px; + right: 5px; +} + +.lobby_players_block { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -ms-flex-pack: distribute; + justify-content: space-around; + height: 100%; + padding-bottom: 50px; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + +.lobby_player_block { + height: 100%; + width: 150px; + border: 1px solid #F79F00; + border-top: none; + border-bottom-left-radius: 20px; + border-bottom-right-radius: 20px; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + font-size: 18px; +} + +.lobby_player_blank { + height: 100%; + width: 150px; + border: 1px solid gray; + border-top: none; + border-bottom-left-radius: 20px; + border-bottom-right-radius: 20px; +} + +.lobby_bottom { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + position: absolute; + bottom: 0; + left: 0; + width: 100%; + padding: 10px 0; +} + +.lobby_start_block { + position: relative; + color: #F79F00; +} + +.lobby_start_game_button, .lobby_cancel_queue_button { + cursor: pointer; +} + +.lobby_start_game_span { + color: gray; +} + +.lobby_countdown_block { + position: absolute; + top: 0; + left: 110%; + display: none; +} + +.lobby_accept_request_bg { + position: fixed; + width: 100vw; + height: 100vh; + top: 0; + left: 0; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + background-color: #A6A6A6; + opacity: 0.8; + z-index: 2; +} + +.lobby_accept_request_button { + width: 300px; + height: 300px; + border-radius: 150px; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + background-color: white; + border: 5px solid #F79F00; + text-transform: uppercase; +} + +.lobby_accept_request_button > span { + border: 2px solid #F79F00; + padding: 5px; + font-size: 24px; + font-weight: bold; + letter-spacing: 0.2em; + cursor: pointer; +} + +.header_friend_invite { + display: block; +} + +.header_friend_invited { + display: none; +} + +.game_content { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + padding: 10px; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + +.game_themes > span { + margin-right: 10px; +} + +.game_questions_block { + width: 100%; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +.game_question { + text-align: center; +} + +.game_answers_block { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + margin: 10px; +} + +.game_answer { + width: 300px; + text-align: center; + cursor: pointer; + padding: 5px 10px; + margin-top: 5px; +} + +.game_answer_button { + background-color: #F79F00; + padding: 3px 7px; + cursor: pointer; + visibility: hidden; +} + +.game_bottom { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + margin-top: 20px; +} + +.results_score_first > td { + background-color: #ffd700; + font-size: 24px; +} + +.results_score_second > td { + background-color: #c0c0c0; + font-size: 20px; +} + +.results_score_third > td { + background-color: #b08d57; + font-size: 16px; +} + +.game_chat_block, .lobby_chat_block { + position: fixed; + bottom: 5px; + left: 5px; + width: 300px; + display: none; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + background-color: white; + border: 1px solid #F79F00; +} + +.game_chat_top, .lobby_chat_top { + padding: 3px; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + width: 100%; + border-bottom: 1px solid #F79F00; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + +.game_chat_messages, .lobby_chat_messages { + height: 170px; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: reverse; + -ms-flex-direction: column-reverse; + flex-direction: column-reverse; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + overflow-y: auto; + width: 100%; +} + +.game_chat_textarea, .lobby_chat_textarea { + width: 100%; + height: 40px; + border: none; + border-top: 1px solid #F79F00; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + +.lobby_chat_open, .game_chat_open { + padding: 3px; + border: 1px solid #F79F00; + position: fixed; + left: 5px; + bottom: 5px; + background-color: white; + cursor: pointer; +} + +.lobby_chat_close, .game_chat_close { + cursor: pointer; +} +/*# sourceMappingURL=games_style.css.map */ \ No newline at end of file diff --git a/dnt/static/css/games_style.css.map b/dnt/static/css/games_style.css.map new file mode 100644 index 0000000..27cce9d --- /dev/null +++ b/dnt/static/css/games_style.css.map @@ -0,0 +1,9 @@ +{ + "version": 3, + "mappings": "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", + "sources": [ + "games_style.scss" + ], + "names": [], + "file": "games_style.css" +} \ No newline at end of file diff --git a/dnt/static/css/games_style.scss b/dnt/static/css/games_style.scss new file mode 100644 index 0000000..7b0b10a --- /dev/null +++ b/dnt/static/css/games_style.scss @@ -0,0 +1,259 @@ +#site_content { + padding: 0 10px; + width: 877px; +} + +.lobby_content { + display: flex; + flex-direction: column; + justify-content: space-between; + width: 100%; + height: calc(100vh - 302px); + position: relative; +} + +.lobby_mode { + position: absolute; + left: 5px; + top: 5px; + display: flex; + align-items: center; + z-index: 1; +} + +.lobby_mode > span { + margin-right: 5px; +} + +.lobby_mode > select { + margin-right: 10px; + border: 1px solid #F79F00; + background-color: white; +} + +.lobby_invitation_rejected { + position: absolute; + top: 5px; + right: 5px; +} + +.lobby_players_block { + display: flex; + justify-content: space-around; + height: 100%; + padding-bottom: 50px; + box-sizing: border-box; +} + +.lobby_player_block { + height: 100%; + width: 150px; + border: 1px solid #F79F00; + border-top: none; + border-bottom-left-radius: 20px; + border-bottom-right-radius: 20px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: 18px; +} + +.lobby_player_blank { + height: 100%; + width: 150px; + border: 1px solid gray; + border-top: none; + border-bottom-left-radius: 20px; + border-bottom-right-radius: 20px; +} + +.lobby_bottom { + display: flex; + justify-content: center; + position: absolute; + bottom: 0; + left: 0; + width: 100%; + padding: 10px 0; +} + +.lobby_start_block { + position: relative; + color: #F79F00; +} + +.lobby_start_game_button, .lobby_cancel_queue_button { + cursor: pointer; +} + +.lobby_start_game_span { + color: gray; +} + +.lobby_countdown_block { + position: absolute; + top: 0; + left: 110%; + display: none; +} + +.lobby_accept_request_bg { + position: fixed; + width: 100vw; + height: 100vh; + top: 0; + left: 0; + display: flex; + justify-content: center; + align-items: center; + background-color: #A6A6A6; + opacity: 0.8; + z-index: 2; +} + +.lobby_accept_request_button { + width: 300px; + height: 300px; + border-radius: 150px; + display: flex; + justify-content: center; + align-items: center; + background-color: white; + border: 5px solid #F79F00; + text-transform: uppercase; +} + +.lobby_accept_request_button > span { + border: 2px solid #F79F00; + padding: 5px; + font-size: 24px; + font-weight: bold; + letter-spacing: 0.2em; + cursor: pointer; +} + +.header_friend_invite { + display: block; +} + +.header_friend_invited { + display: none; +} + +.game_content { + display: flex; + flex-direction: column; + padding: 10px; + box-sizing: border-box; +} + +.game_themes > span { + margin-right: 10px; +} + +.game_questions_block { + width: 100%; + display: flex; + flex-direction: column; + align-items: center; +} + +.game_question { + text-align: center; +} + +.game_answers_block { + display: flex; + flex-direction: column; + align-items: center; + margin: 10px; +} + +.game_answer { + width: 300px; + text-align: center; + cursor: pointer; + padding: 5px 10px; + margin-top: 5px; +} + +.game_answer_button { + background-color: #F79F00; + padding: 3px 7px; + cursor: pointer; + visibility: hidden; +} + +.game_bottom { + display: flex; + justify-content: center; + margin-top: 20px; +} + +.results_score_first > td { + background-color: #ffd700; + font-size: 24px; +} + +.results_score_second > td { + background-color: #c0c0c0; + font-size: 20px; +} + +.results_score_third > td { + background-color: #b08d57; + font-size: 16px; +} + +.game_chat_block, .lobby_chat_block { + position: fixed; + bottom: 5px; + left: 5px; + width: 300px; + display: none; + flex-direction: column; + background-color: white; + border: 1px solid #F79F00; +} + +.game_chat_top, .lobby_chat_top { + padding: 3px; + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + border-bottom: 1px solid #F79F00; + box-sizing: border-box; +} + +.game_chat_messages, .lobby_chat_messages { + height: 170px; + display: flex; + flex-direction: column-reverse; + align-items: center; + overflow-y: auto; + width: 100%; +} + +.game_chat_textarea, .lobby_chat_textarea { + width: 100%; + height: 40px; + border: none; + border-top: 1px solid #F79F00; + box-sizing: border-box; +} + +.lobby_chat_open, .game_chat_open { + padding: 3px; + border: 1px solid #F79F00; + position: fixed; + left: 5px; + bottom: 5px; + background-color: white; + cursor: pointer; +} + +.lobby_chat_close, .game_chat_close { + cursor: pointer; +} \ No newline at end of file diff --git a/dnt/static/css/style.css b/dnt/static/css/style.css index dd7e76a..3550843 100644 --- a/dnt/static/css/style.css +++ b/dnt/static/css/style.css @@ -56,16 +56,8 @@ h6 { a, a:hover { outline: none; - text-decoration: underline; - color: #F05A00;} -} - -a:hover { text-decoration: none; -} - -a:visited { - color: #9C27B0; + color: #F05A00; } .left { @@ -179,7 +171,15 @@ ol li { color: #FFF; text-transform: uppercase; letter-spacing: 0.1em; + display: flex; + justify-content: space-around; + position: relative; +} + +#delimiter > a { + color: #FFF; } + ul#menu, ul#menu li { float: left; margin: 0; @@ -276,11 +276,6 @@ ul#menu li.selected a:hover { line-height: 1.5em; } -#index-content a, a:hover { - text-decoration: underline; - color: #A4AA04; -} - #index-content a:hover { text-decoration: none; } @@ -414,4 +409,152 @@ table tr td { .lobby_invitation_block { display: none; + position: absolute; + bottom: 100%; + right: 0; + width: 100%; + box-sizing: border-box; + justify-content: space-around; + padding: 5px 0; + background-color: white; + color: black; +} + +.lobby_invitation_accept, .lobby_invitation_reject { + cursor: pointer; +} + +.header_friends_button { + position: relative; + cursor: pointer; +} + +.header_friends_block { + display: none; + flex-direction: column; + width: 150px; + position: absolute; + top: 100%; + left: -50px; + color: white; + background-color: #F79F00; + text-transform: none; + cursor: default; + z-index: 2; +} + +.header_friends_add { + padding: 5px; + color: white; +} + +.header_friend { + display: flex; + align-items: center; + justify-content: space-between; + padding: 5px; + border-top: 1px solid gray; +} + +.header_friend_icons { + display: flex; + align-items: center; +} + +.header_friend_icon { + width: 15px; + margin-left: 5px; + cursor: pointer; +} + +.header_friend_invite { + display: none; +} + +.friend_chat_block { + position: fixed; + bottom: 5px; + right: 5px; + width: 300px; + display: none; + flex-direction: column; + background-color: white; + border: 1px solid #F79F00; +} + +.friend_chat_top { + padding: 3px; + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + box-sizing: border-box; + border-bottom: 1px solid #F79F00; +} + +.friend_chat_messages { + height: 170px; + display: flex; + flex-direction: column-reverse; + align-items: center; + overflow-y: auto; + width: 100%; +} + +.friend_chat_textarea { + width: 100%; + height: 30px; + border: none; + border-top: 1px solid #F79F00; + box-sizing: border-box; +} + +.friend_chat_close { + cursor: pointer; +} + +.chat_date { + margin: 5px 0; +} + +.chat_sent, .chat_received { + display: flex; + flex-direction: column; + width: 100%; + box-sizing: border-box; + padding: 0 5px 5px; +} + +.chat_sent { + align-items: flex-end; +} + +.chat_received { + align-items: flex-start; +} + +.chat_message_sender { + margin: 5px 0 3px; +} + +.chat_message_text { + border: 1px solid #F79F00; + border-radius: 5px; + padding: 2px 5px; + max-width: 60%; + position: relative; +} + +.chat_message_time { + position: absolute; + bottom: 0; + font-size: 12px; +} + +.chat_sent > .chat_message_text > .chat_message_time { + right: calc(100% + 5px); +} + +.chat_received > .chat_message_text > .chat_message_time { + left: calc(100% + 5px); } \ No newline at end of file diff --git a/dnt/static/img/chat_open_icon.png b/dnt/static/img/chat_open_icon.png new file mode 100644 index 0000000..939273c Binary files /dev/null and b/dnt/static/img/chat_open_icon.png differ diff --git a/dnt/static/img/invite_icon.webp b/dnt/static/img/invite_icon.webp new file mode 100644 index 0000000..75552ab Binary files /dev/null and b/dnt/static/img/invite_icon.webp differ diff --git a/dnt/static/js/game.js b/dnt/static/js/game.js index 0c920ad..06bd2ae 100644 --- a/dnt/static/js/game.js +++ b/dnt/static/js/game.js @@ -53,9 +53,26 @@ window.addEventListener('load', () => { // обводка правильного ответа и ответа пользователя, если он не правильный, зелёным и красным соответственно $('.chosen_answer').css('border', '1px solid red'); $(`#answer_${data.correct_answer.id}`).css('border', '1px solid green'); + $('.game_answer_button').css('visibility', ''); // переход на страницу с результатами } else if(action == 'show_results') { window.location.href = data['url']; + } else if (action == 'chat_message') { + let message = JSON.parse(data['message'])[0]; + let message_sender = data['sender']; + let text = message.fields.text; + let date = message.fields.created_at.slice(0, 10); + let time = message.fields.created_at.slice(11, 16); + if($('.game_chat_messages > .chat_date').length == 0 || $('.game_chat_messages > .chat_date')[0].outerText != date) { + $('.game_chat_messages').prepend(`${date}`) + } + if (message.fields.sender == parseInt(user_id)) { + $('.game_chat_messages').prepend(`
${message_sender} + ${text}${time}
`); + } else { + $('.game_chat_messages').prepend(`
${message_sender} + ${text}${time}
`); + } } }; @@ -88,6 +105,7 @@ window.addEventListener('load', () => { $(document).on('click', '.game_answer', (event) => { // если ответ уже отправлен, ничего не происходит if(!is_answered) { + $('.game_answer_button').css('visibility', 'visible'); $('.chosen_answer').css('border', ''); $('.chosen_answer').removeClass('chosen_answer'); event.target.style.border = '1px solid black'; @@ -111,4 +129,63 @@ window.addEventListener('load', () => { notificationSocket.close(); }); + $('.game_chat_close').on('click', () => { + $('.game_chat_block').css('display', ''); + }); + + $('.game_chat_open').on('click', () => { + $('.game_chat_block').css('display', 'flex'); + $.ajax({ + method: "get", + url: "/chat/load_messages/", + data: {type: 'game'}, + success: (data) => { + let messages = data['messages']; + if (messages.length > 0) { + let date = messages[0].created_at.slice(0, 10); + let html_string = ''; + for (let message of messages) { + let message_date = message.created_at.slice(0, 10); + if(date != message_date) { + html_string += `${date}`; + date = message_date; + } + let time = message.created_at.slice(11, 16); + let message_sender = data['players'][message.sender_id]; + if (message.sender_id == parseInt(user_id)) { + html_string += `
${message_sender} + ${message.text}${time}
`; + }else{ + html_string += `
${message_sender} + ${message.text}${time}
`; + } + }; + html_string += `${date}`; + $('.game_chat_messages').html(html_string); + }; + }, + error: (data) => { + } + }) + }); + + $('.game_chat_textarea').on('keydown', (event) => { + + if (event.keyCode == 13) { + event.preventDefault(); + let chat_message = event.target.value; + event.target.value = ''; + $.ajax({ + method: "get", + url: "/chat/create_messages/", + data: {message: chat_message, type: 'game'}, + success: (data) => { + + }, + error: (data) => { + } + }) + } + }) + }); \ No newline at end of file diff --git a/dnt/static/js/queue.js b/dnt/static/js/queue.js index 675bd3c..fe40048 100644 --- a/dnt/static/js/queue.js +++ b/dnt/static/js/queue.js @@ -14,8 +14,8 @@ window.addEventListener('load', () => { }); }); - $(document).on('click', '.lobby_invite_friend', (event) => { - let friend_id = event.target.id.replace('friend_', ''); + $(document).on('click', '.header_friend_invite', (event) => { + let friend_id = event.target.id.replace('invite_friend_', ''); let friend_name = event.target.innerHTML; // запуск сокета @@ -28,7 +28,7 @@ window.addEventListener('load', () => { console.log('open') console.log(e) friendSocket.send( - JSON.stringify({'message': {'action': 'invitation', 'sender': {'pk': user_id, 'nickname': $('.lobby_users>p:first-child').html()}}}) + JSON.stringify({'message': {'action': 'invitation', 'sender': {'pk': user_id, 'nickname': $('.lobby_the_player>span:first-child').html()}}}) ) } @@ -61,42 +61,6 @@ window.addEventListener('load', () => { } }); - $(document).on('click', '.lobby_invitation_accept', () => { - $.ajax({ - method: "get", - url: "/games/join_lobby/", - data: {sender_id: sender['pk']}, - success: (data) => { - if(data != 'full') { - let head = data.slice(data.match(//m).index) - let body = data.slice(data.match(//m).index) - $('head').html(head); - $('body').html(body); - } else { - sender = undefined; - $('.lobby_invitation_nickname').html(''); - $('.lobby_invitation_accept').css('display', 'none'); - $('.lobby_invitation_reject').css('display', 'none'); - }; - userSocket.send( - JSON.stringify({'message': {'action': 'accept'}}) - ); - }, - error: (data) => { - } - }); - }); - - $(document).on('click', '.lobby_invitation_reject', () => { - sender = undefined; - $('.lobby_invitation_nickname').html(''); - $('.lobby_invitation_accept').css('display', 'none'); - $('.lobby_invitation_reject').css('display', 'none'); - userSocket.send( - JSON.stringify({'message': {'action': 'reject'}}) - ); - }); - // обработчик события нажатия на кнопку поиска игры $(document).on('click', '.lobby_start_game_button', (event) => { // необходимые изменения интерфейса @@ -153,4 +117,63 @@ window.addEventListener('load', () => { quit_lobby(); }); + $('.lobby_chat_close').on('click', () => { + $('.lobby_chat_block').css('display', ''); + }); + + $('.lobby_chat_open').on('click', () => { + $('.lobby_chat_block').css('display', 'flex'); + $.ajax({ + method: "get", + url: "/chat/load_messages/", + data: {type: 'lobby'}, + success: (data) => { + let messages = data['messages']; + if (messages.length > 0) { + let date = messages[0].created_at.slice(0, 10); + let html_string = ''; + for (let message of messages) { + let message_date = message.created_at.slice(0, 10); + if(date != message_date) { + html_string += `${date}`; + date = message_date; + } + let time = message.created_at.slice(11, 16); + let message_sender = data['players'][message.sender_id]; + if (message.sender_id == parseInt(user_id)) { + html_string += `
${message_sender} + ${message.text}${time}
`; + }else{ + html_string += `
${message_sender} + ${message.text}${time}
`; + } + }; + html_string += `${date}`; + $('.lobby_chat_messages').html(html_string); + }; + }, + error: (data) => { + } + }) + }); + + $('.lobby_chat_textarea').on('keydown', (event) => { + + if (event.keyCode == 13) { + event.preventDefault(); + let chat_message = event.target.value; + event.target.value = ''; + $.ajax({ + method: "get", + url: "/chat/create_messages/", + data: {message: chat_message, type: 'lobby'}, + success: (data) => { + + }, + error: (data) => { + } + }) + } + }) + }); \ No newline at end of file diff --git a/dnt/static/js/queue_functions.js b/dnt/static/js/queue_functions.js index 632f2de..f418085 100644 --- a/dnt/static/js/queue_functions.js +++ b/dnt/static/js/queue_functions.js @@ -1,15 +1,24 @@ function start_count() { - $('#min').html(min); - $('#sec').html(sec); + $('.lobby_countdown_block').css('display', 'block'); + $('#min').html('0' + min); + $('#sec').html('0' + sec); interval = window.setInterval(() => { if(sec == 59) { sec = 0; min++; - $('#min').html(min); + if(min < 10) { + $('#min').html('0' + min); + } else { + $('#min').html(min); + } } else { sec++; } - $('#sec').html(sec); + if(sec < 10) { + $('#sec').html('0' + sec); + } else { + $('#sec').html(sec); + } }, 1000); } @@ -34,9 +43,9 @@ function create_queue_socket(queue_id) { // запрос на подтверждение - создание кнопки и установление таймайта на её исчезновение if(action == 'accept_request') { - $('body').append('Подтвердить'); + $('body').append('
Подтвердить
'); window.setTimeout(() => { - $('.lobby_accept_request_button').remove(); + $('.lobby_accept_request_bg').remove(); accept_count = 0; themes = []; if(accepted == false) { @@ -111,6 +120,7 @@ function cancel_queue(is_canceler) { window.clearInterval(interval); sec = 0; min = 0; + $('.lobby_countdown_block').css('display', ''); $('#sec').html(''); $('#min').html(''); diff --git a/dnt/static/js/user_websocket.js b/dnt/static/js/user_websocket.js index 62f1c4a..f694a9d 100644 --- a/dnt/static/js/user_websocket.js +++ b/dnt/static/js/user_websocket.js @@ -19,8 +19,7 @@ window.addEventListener('load', () => { if(action == 'invitation') { sender = data['sender']; $('.lobby_invitation_nickname').html(`Принять приглашение от ${sender['nickname']}`); - $('.lobby_invitation_accept').css('display', 'inline'); - $('.lobby_invitation_reject').css('display', 'inline'); + $('.lobby_invitation_block').css('display', 'flex'); } else if(action == 'queue') { // необходимые изменения интерфейса $('.lobby_start_game_span').html('Отменить поиск'); @@ -32,9 +31,17 @@ window.addEventListener('load', () => { } else if(action == 'cancel_queue') { cancel_queue(false); } else if(action == 'player_quit') { + current_players -= 1; $(`#user_${data['quitter_pk']}`).remove(); - $('.lobby_invite_block').css('display', ''); - $('.lobby_invite_block').append(`${data['quitter_nickname']}`); + $(`#invite_friend_${data['quitter_pk']}`).addClass('header_friend_invite'); + $(`#invite_friend_${data['quitter_pk']}`).removeClass('header_friend_invited'); + $('.header_friend_invite').css('display', ''); + let blank_string = '
'; + if(current_players % 2 == 1) { + $('.lobby_the_player').before(blank_string); + } else { + $('.lobby_the_player').after(blank_string); + } if(data['lobby_leader'] && data['new_leader_pk'] == user_id) { $('.lobby_start_game_span').addClass('lobby_start_game_button'); $('.lobby_start_game_span').removeClass('lobby_start_game_span'); @@ -45,21 +52,63 @@ window.addEventListener('load', () => { $('#mode_ranked').css('display', ''); }; } else if(action == 'player_join') { - $(`#friend_${data['joiner_pk']}`).remove(); - $('.lobby_users').append(`

${data['joiner_nickname']}

`); + current_players += 1; + $(`#invite_friend_${data['quitter_pk']}`).removeClass('header_friend_invite'); + $(`#invite_friend_${data['quitter_pk']}`).addClass('header_friend_invited'); + let player_string = `
${data['joiner_nickname']}
`; + if(current_players % 2 == 1) { + $('.lobby_players_block>div:first-child').remove(); + $('.lobby_the_player').before(player_string); + } else { + $('.lobby_players_block>div:last-child').remove(); + $('.lobby_the_player').after(player_string); + } $('#mode_ranked').css('display', 'none'); if(data['last_place']) { - $('.lobby_invite_block').css('display', 'none'); + $('.header_friend_invite').css('display', 'none'); }; } else if(action == 'add_theme') { - let html_string = ''; for (let theme of data['themes']) { html_string += `` }; html_string += ''; - $('body').append(html_string); + $('.lobby_mode').append(html_string); } else if(action == 'delete_theme') { $('.lobby_theme').remove(); + } else if(action == 'chat_message') { + let message = JSON.parse(data['message'])[0]; + let message_sender = data['sender']; + let text = message.fields.text; + let date = message.fields.created_at.slice(0, 10); + let time = message.fields.created_at.slice(11, 16); + if (data['type'] == 'friend') { + if($('.friend_chat_messages > .chat_date').length == 0 || $('.friend_chat_messages > .chat_date')[0].outerText != date) { + $('.friend_chat_messages').prepend(`${date}`) + } + if (message.fields.sender == parseInt(user_id)) { + $('.friend_chat_messages').prepend(`
${message_sender} + ${text}${time}
`); + } else { + if($('.friend_chat_block').css('display') == 'none' || $('.friend_chat_name').html != data['sender']) { + $(`#chat_friend_${message.fields.sender}`).click(); + } else { + $('.friend_chat_messages').prepend(`
${message_sender} + ${text}${time}
`); + } + } + } else if (data['type'] == 'lobby'){ + if($('.lobby_chat_messages > .chat_date').length == 0 || $('.lobby_chat_messages > .chat_date')[0].outerText != date) { + $('.lobby_chat_messages').prepend(`${date}`) + } + if (message.fields.sender == parseInt(user_id)) { + $('.lobby_chat_messages').prepend(`
${message_sender} + ${text}${time}
`); + } else { + $('.lobby_chat_messages').prepend(`
${message_sender} + ${text}${time}
`); + } + } } }; @@ -74,4 +123,111 @@ window.addEventListener('load', () => { console.log('error') console.log(e) } + + $(document).on('click', '.header_friends_button', (event) => { + if ($('.header_friends_block').css('display') == 'none') { + $('.header_friends_block').css('display', 'flex'); + } else if (event.target.classList[0] == 'header_friends_button') { + $('.header_friends_block').css('display', ''); + } + }) + + $(document).on('click', '.lobby_invitation_accept', () => { + $.ajax({ + method: "get", + url: "/games/join_lobby_ajax/", + data: {sender_id: sender['pk']}, + success: (data) => { + userSocket.send( + JSON.stringify({'message': {'action': 'accept'}}) + ); + if(data != 'full') { + window.location.href = data['url']; + } else { + sender = undefined; + $('.lobby_invitation_nickname').html(''); + $('.lobby_invitation_block').css('display', 'none'); + }; + }, + error: (data) => { + } + }); + }); + + $(document).on('click', '.lobby_invitation_reject', () => { + sender = undefined; + $('.lobby_invitation_nickname').html(''); + $('.lobby_invitation_block').css('display', ''); + userSocket.send( + JSON.stringify({'message': {'action': 'reject'}}) + ); + }); + + $('.friend_chat_close').on('click', () => { + $('.friend_chat_block').css('display', ''); + }); + + $('.header_friend_chat').on('click', (event) => { + $('.friend_chat_block').css('display', 'flex'); + let friend_pk = parseInt(event.target.id.replace('chat_friend_', '')); + $.ajax({ + method: "get", + url: "/chat/load_messages/", + data: {friend_pk: friend_pk, type: 'friend'}, + success: (data) => { + let messages = data['messages']; + if (messages.length > 0) { + let date = messages[0].created_at.slice(0, 10); + let html_string = ''; + for (let message of messages) { + let message_date = message.created_at.slice(0, 10); + if(date != message_date) { + html_string += `${date}`; + date = message_date; + } + let time = message.created_at.slice(11, 16); + if (message.sender_id == parseInt(user_id)) { + let message_sender = data['user_nickname']; + html_string += `
${message_sender} + ${message.text}${time}
`; + }else{ + let message_sender = data['friend_nickname']; + html_string += `
${message_sender} + ${message.text}${time}
`; + } + }; + html_string += `${date}`; + $('.friend_chat_messages').html(html_string); + }; + $('.friend_chat_name').html(data['friend_nickname']); + $('.friend_chat_textarea').attr('id', `textarea_${friend_pk}`); + }, + error: (data) => { + } + }) + }); + + + $('.friend_chat_textarea').on('keydown', (event) => { + + if (event.keyCode == 13) { + event.preventDefault(); + let reciever_pk = parseInt(event.target.id.replace('textarea_', '')); + let chat_message = event.target.value; + event.target.value = ''; + $.ajax({ + method: "get", + url: "/chat/create_messages/", + data: {sender: user_id, receiver: reciever_pk, message: chat_message, type: 'friend'}, + success: (data) => { + + }, + error: (data) => { + } + }) + } + }) + + + }); \ No newline at end of file diff --git a/dnt/user_profile/templates/user_profile/friends.html b/dnt/user_profile/templates/user_profile/friends.html index 8cecb53..aecb4e9 100644 --- a/dnt/user_profile/templates/user_profile/friends.html +++ b/dnt/user_profile/templates/user_profile/friends.html @@ -1,14 +1,40 @@ +{% extends "main/base.html" %} +{% load static %} +{% block title %} + Список друзей: +{% endblock %} + +{% block body %} + {% include "main/includes/inc-info.html" %} + +

Список друзей

+ + + + + + + + + + + -{% block content %} -

Список друзей

-
    {% for friend in friends %} -
  • Имя-{{ friend.username }} Дата рождения-({{ friend.birthdate}}) Уровень-{{friend.level}}
  • +
+ + + + + + {% empty %}
  • Вы не добавили еще ни одного друга
  • {% endfor %} - + +
    НикнеймДата рожденияУровень игрокаEmail
    {{ friend.username }}{{ friend.birthdate }}{{ friend.level }}{{ friend.email }}
    +

    Назад

    {% endblock %} diff --git a/dnt/user_profile/templates/user_profile/games_list.html b/dnt/user_profile/templates/user_profile/games_list.html new file mode 100644 index 0000000..cf8351d --- /dev/null +++ b/dnt/user_profile/templates/user_profile/games_list.html @@ -0,0 +1,33 @@ +{% extends "main/base.html" %} +{% load static %} + +{% block title %} + Мои игры +{% endblock %} + +{% block body %} + {% include "main/includes/inc-info.html" %} +

    Мои игры:

    + + + + + + + + + {% if games %} + {% for game in games %} + + + + + {% endfor %} + +
    Тип игрыНачало игры
    {{ game.display_type }}{{ game.get_time }}
    + {% else %} +

    Игры не найдены.

    + {% endif %} +

    Назад

    +{% endblock %} + diff --git a/dnt/user_profile/templates/user_profile/leaderboard.html b/dnt/user_profile/templates/user_profile/leaderboard.html index 2ce1426..a31ce80 100644 --- a/dnt/user_profile/templates/user_profile/leaderboard.html +++ b/dnt/user_profile/templates/user_profile/leaderboard.html @@ -1,29 +1,29 @@ - - - - - Rating - - +{% extends "main/base.html" %} +{% load static %} + +{% block title %} + Профиль +{% endblock %} + +{% block body %} + {% include "main/includes/inc-info.html" %} - + {% for player in players %} - + {% endfor %}
    НикнеймОпыт игрока Уровень игрокаОпыт игрока
    {{ player.username }}{{ player.current_experience }} {{ player.level }}{{ player.current_experience }}
    - - - - +

    Назад

    +{% endblock %} diff --git a/dnt/user_profile/templates/user_profile/manage_friends.html b/dnt/user_profile/templates/user_profile/manage_friends.html index afb59b3..43e0729 100644 --- a/dnt/user_profile/templates/user_profile/manage_friends.html +++ b/dnt/user_profile/templates/user_profile/manage_friends.html @@ -1,13 +1,12 @@ - - - - - Title - - +{% extends "main/base.html" %} +{% load static %} +{% block title %} + Поиск друзей +{% endblock %} -{% block content %} +{% block body %} + {% include "main/includes/inc-info.html" %}

    Поиск друзей

    @@ -19,14 +18,14 @@

    Поиск друзей

    {% for friend in results %}
  • {{ friend.username }} {% if friend in user.friends.all %} - + {% csrf_token %}
  • {% else %} -
    + {% csrf_token %} @@ -52,8 +51,6 @@

    Поиск друзей

    {% endif %}

    Назад

    {% endblock %} - - diff --git a/dnt/user_profile/templates/user_profile/profile.html b/dnt/user_profile/templates/user_profile/profile.html index 52387ef..b44849f 100644 --- a/dnt/user_profile/templates/user_profile/profile.html +++ b/dnt/user_profile/templates/user_profile/profile.html @@ -1,9 +1,22 @@ +{% extends "main/base.html" %} +{% load static %} + +{% block title %} + Профиль +{% endblock %} + +{% block body %} + {% include "main/includes/inc-info.html" %} -{% block content %} -
    +

    Профиль игрока.

    + {% if user.avatar %} + + {% else %} + + {% endif %}

    Ник: {{ user.username }}

    Дата рождения: {{ user.birthdate }}

    {% if user.email == '' %} @@ -13,23 +26,13 @@

    Email: {{ user.email }}

    {% endif %}

    Опыт текущего уровня: {{ user.current_experience }}

    Уровень: {{ user.level }}

    + +
    -

    Мои игры:

    - {% if games %} -
      - {% for game in games %} -
    • {{ user.game.type }} - {{ user.game.started }}
    • - {% endfor %} -
    - {% else %} -

    Игры не найдены.

    - {% endif %} - -

    Список всех игроков

    Пятёрка лидеров

    Список друзей

    +

    Поиск друзей

    +

    Мои игры

    +

    Редактировать профиль

    {% endblock %} - -

    Выйти

    - diff --git a/dnt/user_profile/templates/user_profile/user_list.html b/dnt/user_profile/templates/user_profile/user_list.html deleted file mode 100644 index 5727b80..0000000 --- a/dnt/user_profile/templates/user_profile/user_list.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - User List - - -

    Список всех игроков:

    -
      - {% for user in users %} -
    • Имя-{{ user.username }} Дата рождения-({{ user.birthdate }}) Уровень игрока-({{ user.level}}) Опыт текущего уровня-({{ user.current_experience }})
    • - {% endfor %} -
    -

    Назад

    -

    Поиск друзей

    - - diff --git a/dnt/user_profile/urls.py b/dnt/user_profile/urls.py index 981634d..e771d9a 100644 --- a/dnt/user_profile/urls.py +++ b/dnt/user_profile/urls.py @@ -1,7 +1,5 @@ from django.urls import path import user_profile.views as u_p -from user_profile.views import UserDetailView -from user_profile.views import leaderboard app_name = 'user_profile' @@ -9,8 +7,7 @@ path('', u_p.index, name='index'), path('friends/', u_p.view_friends, name='friends'), path('users//', u_p.UserDetailView.as_view(), name='profile'), - path('users_list/', u_p.user_list, name='user_list'), - path('friends_list/', u_p.manage_friends, name='manage_friends'), - path('users//', u_p.my_games, name='profile'), + path('games_list/', u_p.my_games, name='games_list'), + path('search_friends/', u_p.manage_friends, name='search_friends'), path('leaderboard/', u_p.leaderboard, name='leaderboard'), ] diff --git a/dnt/user_profile/views.py b/dnt/user_profile/views.py index 16daba5..f3594ae 100644 --- a/dnt/user_profile/views.py +++ b/dnt/user_profile/views.py @@ -48,7 +48,7 @@ def manage_friends(request): friend_username = request.POST.get('friend_username') if query: - results = AuthUser.objects.filter(username__icontains=query) + results = AuthUser.objects.filter(username__icontains=query).exclude(username=user) else: results = None @@ -69,18 +69,30 @@ def manage_friends(request): return render(request, 'user_profile/manage_friends.html', context) +# @login_required +# def my_games(request): +# user = request.user +# objs = Game.objects.filter(players=user).order_by('-started') # all() == filter(players=user).order_by('-started') +# games = [x for x in objs if str(user.pk) in x.players] +# context = { +# 'user': user, +# 'games': games, +# } +# return render(request, 'user_profile/profile.html', context) + + +def leaderboard(request): + players = AuthUser.objects.order_by('-level', '-current_experience')[:5] + return render(request, 'user_profile/leaderboard.html', {'players': players}) + + @login_required def my_games(request): user = request.user - obj = Game.objects.filter(players=user).order_by('-started') # all() == filter(players=user).order_by('-started') + obj = Game.objects.all() games = [x for x in obj if str(user.pk) in x.players] context = { 'user': user, 'games': games, } - return render(request, 'user_profile/profile.html', context) - - -def leaderboard(request): - players = AuthUser.objects.order_by('-current_experience')[:5] - return render(request, 'user_profile/leaderboard.html', {'players': players}) + return render(request, 'user_profile/games_list.html', context) diff --git a/dnt/variables.py b/dnt/variables.py index d680f50..bf91834 100644 --- a/dnt/variables.py +++ b/dnt/variables.py @@ -24,3 +24,6 @@ # for models NULLABLE = {"blank": True, "null": True} + +# questions: grade +VOTES = 2