11 Commits

Author SHA1 Message Date
0e3b19fcd9 Advance don't merge 2023-12-12 10:05:13 +01:00
bc892bc157 Advance don't merge 2023-12-12 10:04:46 +01:00
9b523f082f merge with server 2023-12-11 16:15:21 +01:00
78379aea1b Bug fix with username in chat 2023-12-11 16:14:27 +01:00
624fb47e04 merge with server 2023-12-11 14:55:17 +01:00
c178556a2e Add functional research bar 2023-12-11 14:54:39 +01:00
cb5affab48 merge with server 2023-12-11 13:10:17 +01:00
08093627c9 Camille à trop les cramptés, en plus il va voir francis éboué qui est passé chez noz avec son daron qui se dore la biscotte en guadeloupe 2023-12-11 13:09:20 +01:00
208dd206ce merge with server 2023-12-11 10:57:51 +01:00
cee188145d no idea 2023-12-11 10:53:34 +01:00
af9595c447 Don't merge, it's prototypal 2023-11-30 16:36:21 +01:00
21 changed files with 224 additions and 61 deletions

2
.gitignore vendored
View File

@ -3,4 +3,4 @@
db.sqlite3
**/migrations/**
/profiles/static/avatars/*
!/profiles/static/avatars/default
!/profiles/static/avatars/default.env

View File

@ -18,19 +18,27 @@ class ChatConsumer(WebsocketConsumer):
text_data_json = json.loads(text_data)
message = text_data_json['message']
user = self.scope["user"]
if user.is_anonymous:
return;
async_to_sync(self.channel_layer.group_send)(
self.room_group_name,
{
'type':'chat_message',
'username':user.username,
'message':message
}
)
def chat_message(self, event):
message = event['message']
user = self.scope["user"]
if user.is_anonymous:
return;
self.send(text_data=json.dumps({
'type':'chat',
'username':self.scope["user"].username,
'message':message
'username':event['username'],
'message':event['message']
}))

View File

@ -1,3 +1,17 @@
from django.db import models
from django.db.models import IntegerField
from django.contrib.auth.models import User
# Create your models here.
class ChannelModel(models.Model):
pass
class MemberModel(models.Model):
member_id = IntegerField(primary_key=False)
channel_id = IntegerField(primary_key=False)
class MessageModel(models.Model):
channel_id = IntegerField(primary_key=False)
author_id = IntegerField(primary_key=False)
content = models.CharField(max_length=255)
time = models.DateField()

8
chat/serializers.py Normal file
View File

@ -0,0 +1,8 @@
from rest_framework import serializers
from .models import ChannelModel
class ChannelSerializer(serializers.ModelSerializer):
class Meta:
model = ChannelModel
fields = []

9
chat/urls.py Normal file
View File

@ -0,0 +1,9 @@
from django.urls import path
from django.conf import settings
from django.conf.urls.static import static
from . import views
urlpatterns = [
path("<int:pk>", views.ChatView.as_view(), name="chat_page"),
]

View File

@ -1,3 +1,29 @@
from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import authentication, permissions
from rest_framework.authentication import SessionAuthentication
from .models import ChannelModel, MemberModel, MessageModel
# Create your views here.
class ChatView(APIView):
permission_classes = (permissions.IsAuthenticated,)
authentication_classes = (SessionAuthentication,)
def post(self, request, pk):
if (ChannelModel.objects.filter(pk = pk)):
return Response("Channel already exist")
data: dict = request.data
users_id = request.data.get("users_id", [])
if len(users_id) < 2:
return Response("Not enought members to create the channel")
new_channel = ChannelModel()
new_channel.save()
for user_id in users_id:
new_member = MemberModel()
new_member.channel_id = new_channel.pk
new_member.member_id = user_id
new_member.save()
return Response("Channel created")

View File

@ -0,0 +1,17 @@
#app img
{
max-height: 100px;
max-width: 100px;
}
#app ul
{
margin: 5px 0 0 0;
padding: 0 0 0 0;
list-style-type: none;
}
#app li
{
margin: 10px 10px 0 0;
}

View File

@ -0,0 +1,9 @@
class Channel {
constructor(id, members, messages) {
this.id = id;
this.members = members;
this.messages = messages;
}
}
export {Channel}

View File

@ -0,0 +1,19 @@
class Channels {
constructor(client) {
this.client = client;
}
async createChannel(users_id) {
console.log(users_id);
let response = await this.client._post("/api/chat/", {
users_id:users_id
});
let data = await response.json();
if (data == "Channel already exist")
return null;
return data;
}
}
export {Channels}

View File

@ -122,4 +122,4 @@ class Client
}
}
export {Client}
export {Client}

View File

@ -1,6 +1,7 @@
import LoginView from "./views/accounts/LoginView.js";
import Dashboard from "./views/Dashboard.js";
import Settings from "./views/Settings.js";
import Search from "./views/Search.js";
import Chat from "./views/Chat.js";
import HomeView from "./views/HomeView.js";
import RegisterView from "./views/accounts/RegisterView.js";
@ -10,7 +11,6 @@ import { Client } from "./api/client.js";
import AbstractRedirectView from "./views/AbstractRedirectView.js";
import MeView from "./views/MeView.js";
import ProfilePageView from "./views/profiles/ProfilePageView.js";
import ProfilesView from "./views/profiles/ProfilesView.js";
let client = new Client(location.protocol + "//" + location.host)
@ -35,12 +35,12 @@ const navigateTo = async (uri) => {
const router = async (uri) => {
const routes = [
{ path: "/", view: Dashboard },
{ path: "/profiles", view: ProfilesView},
{ path: "/profiles/:id", view: ProfilePageView },
{ path: "/settings", view: Settings },
{ path: "/login", view: LoginView },
{ path: "/logout", view: LogoutView },
{ path: "/register", view: RegisterView },
{ path: "/search", view: Search },
{ path: "/chat", view: Chat },
{ path: "/home", view: HomeView },
{ path: "/me", view: MeView },
@ -96,4 +96,4 @@ document.addEventListener("DOMContentLoaded", () => {
router(location.pathname);
});
export { client, navigateTo }
export { client, navigateTo }

View File

@ -1,10 +1,10 @@
import AbstractAuthentifiedView from "./AbstractAuthentifiedView.js";
import AbstractView from "./AbstractView.js";
export default class extends AbstractAuthentifiedView {
export default class extends AbstractView {
constructor(params) {
super(params, "Chat");
let url = `wss://${window.location.host}/ws/socket-server/`
let url = `ws://${window.location.host}/ws/socket-server/`
this.chatSocket = new WebSocket(url)
this.chatSocket.onmessage = function(e){
@ -44,7 +44,7 @@ export default class extends AbstractAuthentifiedView {
<h1>Chat</h1>
<form id="form">
<input type="text" name="message" />
<input type="text" name="message" placeholder="message"/>
</form>
<div id="messages">

View File

@ -0,0 +1,85 @@
import AbstractView from "./AbstractView.js";
import {client} from "../index.js";
export default class extends AbstractView {
constructor(params) {
super(params, "Search");
}
async postInit() {
let search = document.getElementById("form");
search.addEventListener("input", this.users)
this.users();
}
async users() {
let search = document.getElementById("form").value;
let logged = await client.isAuthentificate();
let users = await client.profiles.all();
let list_users = document.getElementById('list_users');
list_users.innerHTML = "";
users.filter(user => user.username.startsWith(search) == true).forEach((user) => {
var new_user = document.createElement("li");
// username
let username = document.createElement("a");
username.href = `/profiles/${user.user_id}`;
username.appendChild(document.createTextNode(user.username));
new_user.appendChild(username);
// space
new_user.appendChild(document.createTextNode(" "));
// chat
if (logged) {
let chat = document.createElement("a");
let array = [
client.me.user_id,
user.user_id,
];
console.log(client.me.id);
chat.addEventListener("click", async function(){
console.log("click");
await client.channels.createChannel([client.me.user_id , user.user_id]);
});
//chat.href = `/chat`
chat.appendChild(document.createTextNode("Chat"));
new_user.appendChild(chat);
}
// break line
new_user.appendChild(document.createElement("br"));
// avatar
var img = document.createElement("img");
img.src = user.avatar_url;
new_user.appendChild(img);
list_users.appendChild(new_user);
});
//console.log(list_users);
}
async getHtml() {
return `
<link rel="stylesheet" href="/static/css/search.css">
<input id="form" type="text" name="message" placeholder="userbozo"/>
<div id="users">
<ul id="list_users">
</ul>
</div>
`;
}
}

View File

@ -52,4 +52,4 @@ export default class extends AbstractNonAuthentifiedView {
</div>
`;
}
}
}

View File

@ -26,4 +26,4 @@ export default class extends AbstractView {
<a id="username"></a>
`;
}
}
}

View File

@ -1,40 +0,0 @@
import AbstractView from "../AbstractView.js";
import { client } from "../../index.js"
export default class extends AbstractView {
constructor(params) {
super(params, "Profiles");
}
async postInit()
{
let profiles = await client.profiles.all()
let profile_list_element = document.getElementById("profile-list")
profiles.forEach((profile) => {
let profile_element = document.createElement("div");
profile_element.className = "item";
let avatar = document.createElement("img");
avatar.src = profile.avatar_url;
let username = document.createElement("a");
username.href = `/profiles/${profile.user_id}`;
username.appendChild(document.createTextNode(profile.username));
profile_element.appendChild(avatar);
profile_element.appendChild(username);
profile_list_element.appendChild(profile_element)
});
}
async getHtml() {
return `
<link rel="stylesheet" href="/static/css/profiles/profiles.css">
<div id="profile-list">
</div>
`;
}
}

View File

@ -10,10 +10,10 @@
<body>
<nav class="nav">
<a href="/" class="nav__link" data-link>Dashboard</a>
<a href="/profiles" class="nav__link" data-link>Profiles</a>
<a href="/search" class="nav__link" data-link>Search</a>
<a href="/home" class="nav__link" data-link>Home</a>
<a href="/login" class="nav__link" data-link>Login</a>
<a href="/register" class="nav__link" data-link>Register</a>
<a href="/chat" class="nav__link" data-link>Chat</a>
</nav>
<div id="app"></div>
<script type="module" src="{% static 'js/index.js' %}"></script>

6
package-lock.json generated Normal file
View File

@ -0,0 +1,6 @@
{
"name": "ft_transcendence",
"lockfileVersion": 3,
"requires": true,
"packages": {}
}

View File

@ -17,7 +17,7 @@ from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'trancendence.settings')
application = ProtocolTypeRouter({
'http':get_asgi_application(),
'http':get_asgi_application(),
'websocket':AuthMiddlewareStack(
URLRouter(
chat.routing.websocket_urlpatterns

View File

@ -46,6 +46,7 @@ INSTALLED_APPS = [
'accounts.apps.AccountsConfig',
'profiles.apps.ProfilesConfig',
'frontend.apps.FrontendConfig',
'chat.apps.ChatConfig',
'corsheaders',
'rest_framework',
@ -148,4 +149,4 @@ STATIC_URL = 'static/'
# Default primary key field type
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

View File

@ -21,5 +21,6 @@ urlpatterns = [
path('admin/', admin.site.urls),
path('api/profiles/', include('profiles.urls')),
path('api/accounts/', include('accounts.urls')),
path('api/chat/', include('chat.urls')),
path('', include('frontend.urls')),
]
]