1
0
forked from PGL/Clyde

responses and general modifications

This commit is contained in:
Debucquoy Anthony 2024-04-09 23:41:24 +02:00
parent 7b0d76dae8
commit 106bf96a98
Signed by untrusted user: tonitch
GPG Key ID: A78D6421F083D42E
8 changed files with 105 additions and 57 deletions

View File

@ -17,6 +17,7 @@ import org.springframework.web.bind.annotation.RestController;
import jakarta.websocket.server.PathParam; import jakarta.websocket.server.PathParam;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import ovh.herisson.Clyde.Repositories.CourseRepository; import ovh.herisson.Clyde.Repositories.CourseRepository;
import ovh.herisson.Clyde.Repositories.Msg.AnswerRepository;
import ovh.herisson.Clyde.Repositories.Msg.ForumRepository; import ovh.herisson.Clyde.Repositories.Msg.ForumRepository;
import ovh.herisson.Clyde.Repositories.Msg.TopicRepository; import ovh.herisson.Clyde.Repositories.Msg.TopicRepository;
import ovh.herisson.Clyde.Responses.UnauthorizedResponse; import ovh.herisson.Clyde.Responses.UnauthorizedResponse;
@ -27,6 +28,7 @@ import ovh.herisson.Clyde.Tables.Course;
import ovh.herisson.Clyde.Tables.Role; import ovh.herisson.Clyde.Tables.Role;
import ovh.herisson.Clyde.Tables.Token; import ovh.herisson.Clyde.Tables.Token;
import ovh.herisson.Clyde.Tables.User; import ovh.herisson.Clyde.Tables.User;
import ovh.herisson.Clyde.Tables.Msg.Answer;
import ovh.herisson.Clyde.Tables.Msg.Forum; import ovh.herisson.Clyde.Tables.Msg.Forum;
import ovh.herisson.Clyde.Tables.Msg.Topic; import ovh.herisson.Clyde.Tables.Msg.Topic;
@ -36,7 +38,6 @@ import ovh.herisson.Clyde.Tables.Msg.Topic;
public class ForumController { public class ForumController {
private CourseRepository courseRepo; private CourseRepository courseRepo;
private CourseService courseServ;
private AuthenticatorService authServ; private AuthenticatorService authServ;
private ForumService forumServ; private ForumService forumServ;
private ForumRepository forumRepo; private ForumRepository forumRepo;
@ -69,7 +70,7 @@ public class ForumController {
@GetMapping("/forum/{id}") @GetMapping("/forum/{id}")
public ResponseEntity<List<Topic>> getTopicsFromForumId(@RequestHeader("Authorization") String token, @PathVariable long id){ public ResponseEntity<List<Topic>> getTopicsFromForumId(@RequestHeader("Authorization") String token, @PathVariable long id){
User u = authServ.getUserFromToken(token); User u = authServ.getUserFromToken(token);
if(u != null){ if(u == null){
return new UnauthorizedResponse<>(null); return new UnauthorizedResponse<>(null);
} }
return new ResponseEntity<>(forumRepo.findById(id).orElse(null).getTopics(), HttpStatus.OK); return new ResponseEntity<>(forumRepo.findById(id).orElse(null).getTopics(), HttpStatus.OK);
@ -79,7 +80,7 @@ public class ForumController {
public ResponseEntity<Topic> postTopicToForum(@RequestHeader("Authorization") String token, @PathVariable long id, @RequestBody Topic data){ public ResponseEntity<Topic> postTopicToForum(@RequestHeader("Authorization") String token, @PathVariable long id, @RequestBody Topic data){
User u = authServ.getUserFromToken(token); User u = authServ.getUserFromToken(token);
Forum f = forumRepo.findById(id).orElse(null); Forum f = forumRepo.findById(id).orElse(null);
if(!f.getWriters().contains(u)){ if(!(f.getWriters().contains(u) || u.getRole() == Role.Admin)){
return new UnauthorizedResponse<>(null); return new UnauthorizedResponse<>(null);
} }
forumServ.createTopic(f, data); forumServ.createTopic(f, data);
@ -91,13 +92,25 @@ public class ForumController {
@GetMapping("/forum/post/{id}") @GetMapping("/forum/post/{id}")
public ResponseEntity<Topic> getPost(@RequestHeader("Authorization") String token, @PathVariable long id){ public ResponseEntity<Topic> getPost(@RequestHeader("Authorization") String token, @PathVariable long id){
User u = authServ.getUserFromToken(token); User u = authServ.getUserFromToken(token);
if(u != null){ if(u == null){
return new UnauthorizedResponse<>(null); return new UnauthorizedResponse<>(null);
} }
Topic t = topicRepo.findById(id).orElse(null); Topic t = topicRepo.findById(id).orElse(null);
return new ResponseEntity<>(t, HttpStatus.OK); return new ResponseEntity<>(t, HttpStatus.OK);
} }
@PostMapping("/forum/post/{id}")
// TODO: <tonitch> Create a new post/topic and response to a topic public ResponseEntity<Topic> postTopicToForum(@RequestHeader("Authorization") String token, @PathVariable long id, @RequestBody Answer data){
User u = authServ.getUserFromToken(token);
Topic t = topicRepo.findById(id).orElse(null);
if(t.isLocked() && u.getRole() != Role.Admin){
return new UnauthorizedResponse<>(null);
}
System.out.println(data);
forumServ.answerTopic(t, data, u);
return new ResponseEntity<>(HttpStatus.ACCEPTED);
}
// TODO: <tonitch> Check if authorization to view a post/forum/...
} }

View File

@ -0,0 +1,10 @@
package ovh.herisson.Clyde.Repositories.Msg;
import org.springframework.data.repository.CrudRepository;
import ovh.herisson.Clyde.Tables.Msg.Answer;
public interface AnswerRepository extends CrudRepository<Answer, Long> {
}

View File

@ -5,7 +5,10 @@ import org.springframework.stereotype.Service;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import ovh.herisson.Clyde.Repositories.CourseRepository; import ovh.herisson.Clyde.Repositories.CourseRepository;
import ovh.herisson.Clyde.Repositories.Msg.ForumRepository; import ovh.herisson.Clyde.Repositories.Msg.ForumRepository;
import ovh.herisson.Clyde.Repositories.Msg.TopicRepository;
import ovh.herisson.Clyde.Tables.Course; import ovh.herisson.Clyde.Tables.Course;
import ovh.herisson.Clyde.Tables.User;
import ovh.herisson.Clyde.Tables.Msg.Answer;
import ovh.herisson.Clyde.Tables.Msg.Forum; import ovh.herisson.Clyde.Tables.Msg.Forum;
import ovh.herisson.Clyde.Tables.Msg.Topic; import ovh.herisson.Clyde.Tables.Msg.Topic;
@ -15,6 +18,7 @@ public class ForumService {
private CourseRepository courseRepo; private CourseRepository courseRepo;
private ForumRepository forumRepo; private ForumRepository forumRepo;
private TopicRepository topicRepo;
public void createForum(Course c, Forum f){ public void createForum(Course c, Forum f){
c.addForum(f); c.addForum(f);
@ -25,4 +29,10 @@ public class ForumService {
f.addTopic(data); f.addTopic(data);
forumRepo.save(f); forumRepo.save(f);
} }
public void answerTopic(Topic t, Answer data, User u) {
data.setAuthor(u);
t.addAnswer(data);
topicRepo.save(t);
}
} }

View File

@ -11,7 +11,7 @@ import ovh.herisson.Clyde.Tables.User;
@Entity @Entity
@Data @Data
public class Answers { public class Answer {
@Id @Id
@GeneratedValue(strategy = GenerationType.AUTO) @GeneratedValue(strategy = GenerationType.AUTO)
private int id; private int id;
@ -19,12 +19,9 @@ public class Answers {
@CreationTimestamp @CreationTimestamp
private Date creation; private Date creation;
@ManyToOne
private Topic topic;
private String content; private String content;
@OneToOne @ManyToOne(cascade=CascadeType.ALL)
private User author; private User author;
private boolean anonymous; private boolean anonymous;

View File

@ -20,7 +20,7 @@ public class Forum {
private String name; private String name;
@OneToMany @OneToMany(cascade = CascadeType.ALL)
private List<Topic> topics; private List<Topic> topics;
public void addTopic(Topic t) { public void addTopic(Topic t) {

View File

@ -16,11 +16,16 @@ public class Topic {
private String subject, content; private String subject, content;
@OneToOne @ManyToOne
private User author; private User author;
@OneToMany(mappedBy = "topic", cascade = CascadeType.ALL) @OneToMany(cascade = CascadeType.ALL)
private List<Answers> answers; private List<Answer> answers;
public void addAnswer(Answer a){
answers.add(a);
}
private boolean locked; // true if new messages can be posted private boolean locked; // true if new messages can be posted
} }

View File

@ -9,8 +9,8 @@
import { ref, reactive } from 'vue' import { ref, reactive } from 'vue'
import { getCourses } from '@/rest/courses.js' import { getCourses } from '@/rest/courses.js'
import { ForumsOfCurrentCourse, getForumsOfCourse, createForum } from '@/rest/forum.js' import { ForumsOfCurrentCourse, getForumsOfCourse, createForum } from '@/rest/forum.js'
import { PostsOfCurrentForum, getPostsOfForum } from '@/rest/forum.js' import { PostsOfCurrentForum, getPostsOfForum, createPost } from '@/rest/forum.js'
import { fetchedPost, fetchPost } from '@/rest/forum.js' import { fetchedPost, fetchPost, sendAnswer } from '@/rest/forum.js'
import { getSelf } from '@/rest/Users.js' import { getSelf } from '@/rest/Users.js'
const courses = await reactive(getCourses()); const courses = await reactive(getCourses());
@ -20,6 +20,9 @@ const Role = (await getSelf()).role;
const addForum = ref(false); const addForum = ref(false);
const addForumName = ref(""); const addForumName = ref("");
const addPost = ref(false);
const addPostSubject = ref("");
const addPostContent = ref("");
</script> </script>
@ -36,8 +39,8 @@ const addForumName = ref("");
<button v-if="(Role === 'Admin' || Role === 'Teacher') && ForumsOfCurrentCourse != null " id="createPost" @click="addForum = true">+</button> <button v-if="(Role === 'Admin' || Role === 'Teacher') && ForumsOfCurrentCourse != null " id="createPost" @click="addForum = true">+</button>
</div> </div>
<div id="PostSelector" v-if="PostsOfCurrentForum != null"> <div id="PostSelector" v-if="PostsOfCurrentForum != null">
<div @click="fetchPost(post.id)" class="postItem" v-for="post in PostsOfCurrentForum" :key="post.id">{{ post.name }}</div> <div @click="fetchPost(post.id)" class="postItem" v-for="post in PostsOfCurrentForum" :key="post.id">{{ post.subject }}</div>
<button v-if="Role === 'Admin' || Role === 'Teacher' " id="createPost" @click="createPost()">+</button> <button v-if="Role === 'Admin' || Role === 'Teacher' " id="createPost" @click="addPost = true">+</button>
</div> </div>
<div id="PostViewer" v-if="fetchedPost != null"> <div id="PostViewer" v-if="fetchedPost != null">
<div id="Post"> <div id="Post">
@ -45,21 +48,33 @@ const addForumName = ref("");
{{fetchedPost.content}} {{fetchedPost.content}}
</div> </div>
<div id="Messages"> <div id="Messages">
<p v-for="msg in fetchedPost.messages">{{msg.author}} - {{msg.content}}</p> <p v-for="msg in fetchedPost.answers">{{msg.author.firtName}} {{msg.author.lastName}} - {{msg.content}}</p>
<input v-if=!fetchedPost.locked type="text" placeholder="response" @keyup.enter="sendAnswer(fetchedPost.id, $event.target.value)"/>
</div> </div>
</div> </div>
</div> </div>
<div id="forumAdder" v-if=addForum @click.self="addForum = false"> <div class=popup v-if="addForum || addPost" @click.self="addForum = false; addPost = false" >
<div id="addForumForm">
<!-- Popup to add forum -->
<div id="addForumForm" v-if=addForum @keyup.enter="createForum(selectedCourse, addForumName); addForum = false;">
<label>New Forum:</label> <label>New Forum:</label>
<input type="text" placeholder="Name" v-model=addForumName @keyup.enter="createForum(selectedCourse, $event.target.value); addForum = false;" /> <input type="text" placeholder="Name" v-model=addForumName />
</div> </div>
<!-- Popup to add Post -->
<div id="addPostForm" v-if=addPost>
<label>New Post:</label>
<input type="text" placeholder="subject" v-model=addPostSubject @keyup.enter="createPost(selectedForum, addPostSubject, addPostContent); addForum = false;"/>
<textarea v-model="addPostContent" placeholder=content></textarea>
<input type="submit" value="send" @click="createPost(selectedForum, addPostSubject, addPostContent); addForum = false;">
</div>
</div> </div>
</template> </template>
<style scoped> <style scoped>
#forumAdder{ .popup{
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
@ -84,6 +99,21 @@ const addForumName = ref("");
gap: 10px; gap: 10px;
} }
#addPostForm{
position: relative;
width: 30%;
left: calc(50% - 30% / 2);
top: calc(50% - 50% / 2);
border-radius: 10px;
height: 50%;
background-color: white;
display: flex;
justify-content: center;
align-items: center;
gap: 10px;
}
#app{ #app{
display: grid; display: grid;
width: 100%; width: 100%;

View File

@ -1,3 +1,10 @@
/*******************************************************
* File: forum.js
* Author: Anthony Debucquoy
* Scope: Extension messagerie
* Description: Forum related functions and calls
*******************************************************/
import { ref } from 'vue' import { ref } from 'vue'
import { restGet, restPost, restDelete, restPatch } from './restConsumer.js' import { restGet, restPost, restDelete, restPatch } from './restConsumer.js'
@ -18,17 +25,11 @@ export function createForum(id, name){
* List post of a specified forum * List post of a specified forum
*/ */
export async function getPostsOfForum(id){ export async function getPostsOfForum(id){
PostsOfCurrentForum.value = [ PostsOfCurrentForum.value = await restGet("/forum/" + id);
{ }
id: 1,
name: "Post~1" export function createPost(id, subject, content){
}, restPost("/forum/" + id, {subject: subject, content: content}).then(_ => getPostsOfForum(id));
{
id: 2,
name: "Post~2"
},
]
// PostsCurrentForum.value = await restGet("/forum/" + id);
} }
export const PostsOfCurrentForum = ref(); export const PostsOfCurrentForum = ref();
@ -37,29 +38,11 @@ export const PostsOfCurrentForum = ref();
* Get a post and its responses * Get a post and its responses
*/ */
export async function fetchPost(id){ export async function fetchPost(id){
fetchedPost.value = { fetchedPost.value = await restGet("/forum/post/" + id);
id: 1,
subject: "This is the subject of the post",
content: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.",
messages: [
{
id: 1,
author: "author~1",
content: "J'ai pas copris le message !"
},
{
id: 2,
author: "author~2",
content: "tu as fait une faute dans ton message..."
},
{
id: 3,
author: null,
content: "I'm anonymous noww..."
} }
]
} export function sendAnswer(id, content){
// fetchedPost.value = await restGet("/forum/post/" + id); restPost("/forum/post/" + id, {content: content}).then(_ => fetchPost(id))
} }
export const fetchedPost = ref(); export const fetchedPost = ref();