Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

13 implement post creation endpoints #27

Merged
merged 6 commits into from
Mar 15, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@ __pycache__
.idea

api/.env

api/neurona/.env
11 changes: 11 additions & 0 deletions api/neurona/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,19 @@
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',

]

CORS_ALLOWED_ORIGINS = [
"http://localhost:8000",
]

CORS_ALLOW_ALL_ORIGINS = True #pour les tests



ylked marked this conversation as resolved.
Show resolved Hide resolved
ROOT_URLCONF = "neurona.urls"

TEMPLATES = [
Expand Down
9 changes: 8 additions & 1 deletion api/neurona/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,15 @@
"""
from django.contrib import admin
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from neuronaApp.views import PostsViewSet, CommentsViewSet

router = DefaultRouter()
router.register(r'posts', PostsViewSet)
router.register(r'comments', CommentsViewSet)

urlpatterns = [
path("admin/", admin.site.urls),
path("api/", include("neuronaApp.urls"))
path("api/", include("neuronaApp.urls")),
path('', include(router.urls)),
]
3 changes: 2 additions & 1 deletion api/neuronaApp/serializers/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# Import serializers here
from .space_serializer import SpaceSerializer
from .authentication_serializer import *
from .authentication_serializer import *
from .posts_serializer import *
12 changes: 12 additions & 0 deletions api/neuronaApp/serializers/posts_serializer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from rest_framework import serializers
from neuronaApp.models import Posts, Comments, PostsImages, CommentsImages, Votes, CommentsVotes

class PostsSerializer(serializers.ModelSerializer):
class Meta:
model = Posts
fields = '__all__'

class CommentsSerializer(serializers.ModelSerializer):
class Meta:
model = Comments
fields = '__all__'
1 change: 1 addition & 0 deletions api/neuronaApp/views/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
from .space_view import *
from .authentication_view import PasskeyChallengeView, RegisterView, LoginView
from .user_profile_view import *
from .posts_view import *
12 changes: 12 additions & 0 deletions api/neuronaApp/views/posts_view.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from django.shortcuts import render
from rest_framework import viewsets
from neuronaApp.models import Posts, Comments
from neuronaApp.serializers import PostsSerializer, CommentsSerializer

class PostsViewSet(viewsets.ModelViewSet):
queryset = Posts.objects.all()
serializer_class = PostsSerializer

class CommentsViewSet(viewsets.ModelViewSet):
queryset = Comments.objects.all()
serializer_class = CommentsSerializer
153 changes: 25 additions & 128 deletions frontend/src/components/Post.vue
Original file line number Diff line number Diff line change
@@ -1,141 +1,38 @@
<script setup>
import {onMounted, ref} from "vue";
import router from "@/router";

const props = defineProps({
id: Number,
});

const post = ref({});
const mounted = ref(false);
const vote = ref(null);
const saved = ref(null);
const snackbar = ref(false);

onMounted(async () => {
await new Promise(resolve => setTimeout(resolve, 500));
post.value = {
id: props.id,
link: "/posts/" + props.id,
title: "Hello world",
content: "Hello everyone, this is my first post on this platform. " +
"I hope you like it. I'm a big fan of penguins, so I'll be posting " +
"a lot of penguin-related content. I hope you enjoy it!",
vote_count: 12,
user_upvoted: false,
user_downvoted: true,
comments: 3,
saved: true,
timestamp: "2021-10-10T12:00:00Z",
author: {
id: 1,
username: "kingpenguin",
avatar: "https://nzbirdsonline.org.nz/sites/all/files/2X2A1697%20King%20Penguin%20bol.jpg",
name: "John Doe",
},
space: {
id: 1,
title: "ISC1",
avatar: "",
},
};
vote.value = post.value.user_upvoted ? 0 : post.value.user_downvoted ? 1 : null;
saved.value = post.value.saved ? 0 : null;
mounted.value = true;
});

function toggle_upvote(){
post.value.user_upvoted = !post.value.user_upvoted;
post.value.vote_count += post.value.user_upvoted ? 1 : -1;
post.value.vote_count += post.value.user_downvoted ? 1 : 0;
post.value.user_downvoted = false;
}

function toggle_downvote(){
post.value.user_downvoted = !post.value.user_downvoted;
post.value.vote_count += post.value.user_downvoted ? -1 : 1;
post.value.vote_count += post.value.user_upvoted ? -1 : 0;
post.value.user_upvoted = false;
}

function toggle_save(){
post.value.saved = !post.value.saved;
snackbar.value = post.value.saved;
}

function open_post(){
router.push({ path: post.value.link });
}

</script>

<template>

<v-card
v-if="mounted"
:title="post.author.name"
:subtitle="post.author.username + ' on ' + post.space.title"
:text="post.content"
:prepend-avatar="post.author.avatar"
@click="open_post"
class="ma-4"
:ripple="false"
v-if="mounted"
:title="post.title"
:subtitle="'Posted in ' + post.space.title + ' on ' + new Date(post.created_at).toLocaleDateString()"
:text="post.content"
class="ma-4"
:ripple="false"
@click="open_post"
>
<v-card-text>
{{ post.content }}
</v-card-text>
<v-card-actions>
<v-btn-toggle
v-model="vote"
>
<v-btn
prepend-icon="mdi-arrow-up-bold"
:color="post.user_upvoted ? 'green' : ''"
@click.stop="toggle_upvote"
>
{{ post.vote_count }}
</v-btn>

<v-btn
icon="mdi-arrow-down-bold"
:color="post.user_downvoted ? 'red' : ''"
@click.stop="toggle_downvote"
/>

</v-btn-toggle>

<v-btn-toggle
class="mx-2"
>
<v-btn
prepend-icon="mdi-comment"
>
{{ post.comments }}
</v-btn>
</v-btn-toggle>

<v-spacer/>

<v-btn-toggle
v-model="saved"
>
<v-btn
icon="mdi-bookmark"
@click.stop="toggle_save"
:color="post.saved ? 'primary' : ''"
>
</v-btn>
</v-btn-toggle>

<!-- Placeholder for actions like upvote, downvote, comment, etc. -->
</v-card-actions>
</v-card>

<v-skeleton-loader v-else type="card" class="mx-4"></v-skeleton-loader>
</template>

<v-snackbar
v-model="snackbar"
timeout="2000"
text="Post saved"
/>
<script setup>
import { ref } from 'vue';
import router from '@/router';

</template>
const props = defineProps({
post: Object,
});

const mounted = ref(true);

function open_post() {
router.push({ name: 'PostDetail', params: { postId: props.post.id } });
}
</script>

<style scoped>

Expand Down
41 changes: 30 additions & 11 deletions frontend/src/components/Timeline.vue
Original file line number Diff line number Diff line change
@@ -1,15 +1,34 @@
<script setup>

import Post from "@/components/Post.vue";
</script>

<template>
<Post :id="1" />
<Post :id="1" />
<Post :id="1" />
<Post :id="1" />
<div>
<!-- Iterate over posts and pass post data to the Post component -->
<Post
v-for="post in posts"
:key="post.id"
:post="post"
/>
</div>
</template>

<style scoped>
<script>
import ApiService from '@/services/api';
import Post from "@/components/Post.vue";

</style>
export default {
components: {
Post,
},
data() {
return {
posts: [],
};
},
async created() {
try {
const response = await ApiService.getPosts();
this.posts = response.data;
} catch (error) {
console.error("There was an error fetching the posts:", error);
}
},
};
</script>
29 changes: 29 additions & 0 deletions frontend/src/services/api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// src/services/ApiService.js
import axios from 'axios';

const apiClient = axios.create({
baseURL: 'http://localhost:8000/',
withCredentials: false,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
});

export default {
getPosts() {
return apiClient.get('/posts');
},
createPost(postData) {
return apiClient.post('/posts', postData);
},
upvotePost(postId) {
return apiClient.post(`/posts/${postId}/upvote`); // Assuming your backend is set up to handle this route
},
downvotePost(postId) {
return apiClient.post(`/posts/${postId}/downvote`); // Assuming your backend is set up to handle this route
},
addComment(postId, commentData) {
return apiClient.post(`/posts/${postId}/comments`, commentData);
},
};