Compare commits
15 Commits
jalonA
...
5a4d066c45
Author | SHA1 | Date | |
---|---|---|---|
5a4d066c45
|
|||
f9bcff6d4f
|
|||
7bd745fd5e
|
|||
a96609d2ef
|
|||
cb750b8505
|
|||
9e0db361b8 | |||
7a13d412f1 | |||
9de4b06e75 | |||
123fa97611 | |||
1fad792be7 | |||
acd1262955
|
|||
3d6941ab93
|
|||
de72bd800c
|
|||
b465dcfa92 | |||
73f3df0bc6 |
@ -45,7 +45,7 @@ jobs:
|
||||
distribution: 'temurin'
|
||||
- uses: gradle/gradle-build-action@v3
|
||||
- name: building
|
||||
run: ./gradlew backend:build
|
||||
run: ./gradlew backend:build -x test
|
||||
- name: pushing to the server
|
||||
run: |
|
||||
echo "${{ secrets.SSH_KEY }}" > key
|
||||
|
@ -1,5 +1,6 @@
|
||||
FROM eclipse-temurin:21-jdk-alpine
|
||||
VOLUME /tmp
|
||||
VOLUME /cdn
|
||||
ENV SPRING_PROFILES_ACTIVE=prod
|
||||
COPY build/libs/backend-0.0.1-SNAPSHOT.jar /app.jar
|
||||
ENTRYPOINT ["java", "-jar", "/app.jar"]
|
||||
|
@ -16,6 +16,8 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly("org.projectlombok:lombok")
|
||||
annotationProcessor("org.projectlombok:lombok")
|
||||
implementation("org.springframework.boot:spring-boot-starter-jdbc")
|
||||
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
|
||||
implementation("org.springframework.boot:spring-boot-starter-mail")
|
||||
|
@ -49,11 +49,11 @@ public class MockController {
|
||||
// user part
|
||||
|
||||
|
||||
User herobrine = new User("brine","hero","admin@admin.com","in your WalLs","ShadowsLand",new Date(0), null,Role.Admin,passwordEncoder.encode("admin"));
|
||||
User joe = new User("Mama","Joe","student@student.com","roundabout","DaWarudo",new Date(0), null,Role.Student,passwordEncoder.encode("student"));
|
||||
User meh = new User("Inspiration","lackOf","secretary@secretary.com","a Box","the street",new Date(0), null,Role.Secretary,passwordEncoder.encode("secretary"));
|
||||
User joke = new User("CthemBalls","Lemme","teacher@teacher.com","lab","faculty",new Date(0), null,Role.Teacher,passwordEncoder.encode("teacher"));
|
||||
User jojo = new User("hhoo","yeay","teacher2@teacher2.com","lab","faculty",new Date(0), null,Role.Teacher,passwordEncoder.encode("teacher"));
|
||||
User herobrine = new User("brine","hero","admin@admin.com","behind","ShadowsLand",new Date(0), null,Role.Admin,passwordEncoder.encode("admin"));
|
||||
User joe = new User("Mama","Joe","student@student.com","roundabout","England",new Date(0), null,Role.Student,passwordEncoder.encode("student"));
|
||||
User meh = new User("Polo","Marco","secretary@secretary.com","a Box","Monaco",new Date(0), null,Role.Secretary,passwordEncoder.encode("secretary"));
|
||||
User joke = new User("Gaillard","Corentin","teacher@teacher.com","lab","faculty",new Date(0), null,Role.Teacher,passwordEncoder.encode("teacher"));
|
||||
User jojo = new User("Bridoux","Justin","teacher2@teacher2.com","lab","faculty",new Date(0), null,Role.Teacher,passwordEncoder.encode("teacher"));
|
||||
User lena = new User("Louille","Lena","inscriptionService@InscriptionService.com","no","yes",new Date(0), null,Role.InscriptionService,passwordEncoder.encode("inscriptionService"));
|
||||
mockUsers = new ArrayList<>(Arrays.asList(herobrine,joe,meh,joke,lena,jojo));
|
||||
|
||||
@ -72,7 +72,7 @@ public class MockController {
|
||||
|
||||
Course progra1 = new Course(5,"Programmation et algorithmique 1",joke);
|
||||
Course chemistry1 = new Course(12, "Thermochimie",joke);
|
||||
Course psycho1 = new Course(21, "rien faire t'as cru c'est psycho",joke);
|
||||
Course psycho1 = new Course(21, "Neuroreaction of isolated brain cells",joke);
|
||||
Course commun = new Course(2, "cours commun",joke);
|
||||
|
||||
courseService.save(progra1);
|
||||
|
@ -0,0 +1,84 @@
|
||||
package ovh.herisson.Clyde.EndPoints.Msg;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.HttpStatusCode;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import jakarta.websocket.server.PathParam;
|
||||
import lombok.AllArgsConstructor;
|
||||
import ovh.herisson.Clyde.Repositories.CourseRepository;
|
||||
import ovh.herisson.Clyde.Repositories.Msg.ForumRepository;
|
||||
import ovh.herisson.Clyde.Responses.UnauthorizedResponse;
|
||||
import ovh.herisson.Clyde.Services.AuthenticatorService;
|
||||
import ovh.herisson.Clyde.Services.CourseService;
|
||||
import ovh.herisson.Clyde.Services.Msg.ForumService;
|
||||
import ovh.herisson.Clyde.Tables.Course;
|
||||
import ovh.herisson.Clyde.Tables.User;
|
||||
import ovh.herisson.Clyde.Tables.Msg.Forum;
|
||||
import ovh.herisson.Clyde.Tables.Msg.Topic;
|
||||
|
||||
@RestController
|
||||
@CrossOrigin(originPatterns = "*", allowCredentials = "true")
|
||||
@AllArgsConstructor
|
||||
public class ForumController {
|
||||
|
||||
private CourseRepository courseRepo;
|
||||
private CourseService courseServ;
|
||||
private AuthenticatorService authServ;
|
||||
private ForumService forumServ;
|
||||
private ForumRepository forumRepo;
|
||||
|
||||
//// Endpoints to get and create new forums
|
||||
|
||||
@GetMapping("/forums/{id}")
|
||||
public ResponseEntity<List<Forum>> getForumFromCourseId(@RequestHeader("Authorization") String token, @PathVariable long id){
|
||||
User u = authServ.getUserFromToken(token);
|
||||
if(u != null){
|
||||
return new UnauthorizedResponse<>(null);
|
||||
}
|
||||
return new ResponseEntity<>(courseRepo.findById(id).getForums(), HttpStatus.OK);
|
||||
}
|
||||
|
||||
@PostMapping("/forums/{id}")
|
||||
public ResponseEntity<Forum> createForumOfCourse(@RequestHeader("Authorization") String token, @PathVariable long id, @RequestBody Forum data){
|
||||
User u = authServ.getUserFromToken(token);
|
||||
Course c = courseRepo.findById(id);
|
||||
if(!c.getOwner().equals(u)){
|
||||
return new UnauthorizedResponse<>(null);
|
||||
}
|
||||
forumServ.createForum(c, data);
|
||||
return new ResponseEntity<>(HttpStatus.ACCEPTED);
|
||||
}
|
||||
|
||||
//// Endpoints to get and create forum's topic
|
||||
|
||||
@GetMapping("/forum/{id}")
|
||||
public ResponseEntity<List<Topic>> getTopicsFromForumId(@RequestHeader("Authorization") String token, @PathVariable long id){
|
||||
User u = authServ.getUserFromToken(token);
|
||||
if(u != null){
|
||||
return new UnauthorizedResponse<>(null);
|
||||
}
|
||||
return new ResponseEntity<>(forumRepo.findById(id).orElse(null).getTopics(), HttpStatus.OK);
|
||||
}
|
||||
|
||||
@PostMapping("/forum/{id}")
|
||||
public ResponseEntity<Topic> postTopicToForum(@RequestHeader("Authorization") String token, @PathVariable long id, @RequestBody Topic data){
|
||||
User u = authServ.getUserFromToken(token);
|
||||
Forum f = forumRepo.findById(id).orElse(null);
|
||||
if(!f.getWriters().contains(u)){
|
||||
return new UnauthorizedResponse<>(null);
|
||||
}
|
||||
forumServ.createTopic(f, data);
|
||||
return new ResponseEntity<>(HttpStatus.ACCEPTED);
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package ovh.herisson.Clyde.Repositories.Msg;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
import ovh.herisson.Clyde.Tables.Msg.Forum;
|
||||
|
||||
public interface ForumRepository extends CrudRepository<Forum, Long> {
|
||||
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package ovh.herisson.Clyde.Services.Msg;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import ovh.herisson.Clyde.Repositories.CourseRepository;
|
||||
import ovh.herisson.Clyde.Repositories.Msg.ForumRepository;
|
||||
import ovh.herisson.Clyde.Tables.Course;
|
||||
import ovh.herisson.Clyde.Tables.Msg.Forum;
|
||||
import ovh.herisson.Clyde.Tables.Msg.Topic;
|
||||
|
||||
@Service
|
||||
@AllArgsConstructor
|
||||
public class ForumService {
|
||||
|
||||
private CourseRepository courseRepo;
|
||||
private ForumRepository forumRepo;
|
||||
|
||||
public void createForum(Course c, Forum f){
|
||||
c.addForum(f);
|
||||
courseRepo.save(c);
|
||||
}
|
||||
|
||||
public void createTopic(Forum f, Topic data) {
|
||||
f.addTopic(data);
|
||||
forumRepo.save(f);
|
||||
}
|
||||
}
|
@ -1,10 +1,16 @@
|
||||
package ovh.herisson.Clyde.Tables;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Data;
|
||||
import ovh.herisson.Clyde.Tables.Msg.Forum;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.annotations.OnDelete;
|
||||
import org.hibernate.annotations.OnDeleteAction;
|
||||
|
||||
@Entity
|
||||
@Data
|
||||
public class Course {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
@ -17,6 +23,15 @@ public class Course {
|
||||
@JoinColumn(name = "Users")
|
||||
private User owner;
|
||||
|
||||
//// Extension Messagerie /////
|
||||
@OneToMany
|
||||
private List<Forum> forums;
|
||||
|
||||
public void addForum(Forum f){
|
||||
forums.add(f);
|
||||
}
|
||||
///////////////////////////////
|
||||
|
||||
public Course(int credits, String title, User owner){
|
||||
this.credits = credits;
|
||||
this.title = title;
|
||||
|
@ -0,0 +1,32 @@
|
||||
package ovh.herisson.Clyde.Tables.Msg;
|
||||
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.hibernate.annotations.CreationTimestamp;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Data;
|
||||
import ovh.herisson.Clyde.Tables.User;
|
||||
|
||||
@Entity
|
||||
@Data
|
||||
public class Answers {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private int id;
|
||||
|
||||
@CreationTimestamp
|
||||
private Date creation;
|
||||
|
||||
@ManyToOne
|
||||
private Topic topic;
|
||||
|
||||
private String content;
|
||||
|
||||
@OneToOne
|
||||
private User author;
|
||||
|
||||
private boolean anonymous;
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package ovh.herisson.Clyde.Tables.Msg;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Data;
|
||||
import ovh.herisson.Clyde.Tables.Course;
|
||||
import ovh.herisson.Clyde.Tables.User;
|
||||
|
||||
@Entity
|
||||
@Data
|
||||
public class Forum {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private int id;
|
||||
|
||||
@ManyToOne(cascade = CascadeType.ALL)
|
||||
private Course course;
|
||||
|
||||
private String name;
|
||||
|
||||
@OneToMany
|
||||
private List<Topic> topics;
|
||||
|
||||
public void addTopic(Topic t) {
|
||||
topics.add(t);
|
||||
}
|
||||
|
||||
@OneToMany
|
||||
private List<User> writers; // User who are authorized to create a post
|
||||
|
||||
@OneToMany
|
||||
private List<User> register;
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package ovh.herisson.Clyde.Tables.Msg;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Data;
|
||||
import ovh.herisson.Clyde.Tables.User;
|
||||
|
||||
@Entity
|
||||
@Data
|
||||
public class Topic {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private int id;
|
||||
|
||||
private String subject, content;
|
||||
|
||||
@OneToOne
|
||||
private User author;
|
||||
|
||||
@OneToMany(mappedBy = "topic", cascade = CascadeType.ALL)
|
||||
private List<Answers> answers;
|
||||
|
||||
private boolean locked; // true if new messages can be posted
|
||||
}
|
@ -3,6 +3,8 @@ package ovh.herisson.Clyde.Tables;
|
||||
import jakarta.persistence.*;
|
||||
import java.util.Date;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
|
||||
@Entity
|
||||
@Table(name = "Users")
|
||||
@ -18,7 +20,8 @@ public class User {
|
||||
private String country;
|
||||
private Date birthDate;
|
||||
private String profilePictureUrl;
|
||||
private ovh.herisson.Clyde.Tables.Role role;
|
||||
private Role role;
|
||||
@JsonIgnore
|
||||
private String password;
|
||||
public User(String lastName, String firstName, String email, String address,
|
||||
String country, Date birthDate, String profilePictureUrl, Role role, String password)
|
||||
|
@ -88,14 +88,14 @@ public class UserControllerTest {
|
||||
tokenService.saveToken(godToken);
|
||||
|
||||
//Can god post herobrine himself ?
|
||||
User herobrine = new User("brine","hero","herobrine@admin.com","in your WalLs","ShadowsLand",new Date(0), null,Role.Student,"test");
|
||||
User herobrine = new User("brine","hero","herobrine@student.com","in your WalLs","ShadowsLand",new Date(0), null,Role.Student,"test");
|
||||
|
||||
with().body(herobrine).contentType(ContentType.JSON).header("Authorization", godToken.getToken()).when().request("POST", "/user").then().statusCode(201);
|
||||
|
||||
userRepository.delete(herobrine);
|
||||
|
||||
//Can noob post herobrine without authorizations (no)
|
||||
User noob = new User("boon","noob","noob@admintkt.com","everywhere","every",new Date(0), null, Role.Student,"noob");
|
||||
User noob = new User("boon","noob","noob@student.com","everywhere","every",new Date(0), null, Role.Student,"noob");
|
||||
Token noobToken = new Token(noob, tokenService.generateNewToken(), new Date());
|
||||
userRepository.save(noob);
|
||||
tokenService.saveToken(noobToken);
|
||||
@ -105,7 +105,7 @@ public class UserControllerTest {
|
||||
|
||||
@Test
|
||||
public void userGetTest(){
|
||||
User herobrine = new User("brine","hero","herobrine@admin.com","in your WalLs","ShadowsLand",new Date(0), null,Role.Student,"test");
|
||||
User herobrine = new User("brine","hero","herobrine@student.com","in your WalLs","ShadowsLand",new Date(0), null,Role.Student,"test");
|
||||
userRepository.save(herobrine);
|
||||
|
||||
Token t = new Token(herobrine, tokenService.generateNewToken(), new Date());
|
||||
|
@ -70,7 +70,7 @@ class TokenServiceTest {
|
||||
ArrayList<Token> tokenList = new ArrayList<>();
|
||||
GregorianCalendar gc = new GregorianCalendar();
|
||||
|
||||
User malveillant = new User("mechant", "veutdestoken", "donnezmoidestoken@mail.com", "secret", "secret", null, null, null, "secret");
|
||||
User malveillant = new User("Cargo", "John", "CargoJ@mail.com", "secret", "secret", null, null, null, "secret");
|
||||
userRepository.save(malveillant);
|
||||
|
||||
for (int i = 0; i < 20; i++){
|
||||
|
@ -52,7 +52,7 @@ window.addEventListener('hashchange', () => {
|
||||
<a class="icon" href="#Notifications">
|
||||
<div class="fa-solid fa-bell" style="margin-top: 7px; margin-bottom: 3px;"></div>
|
||||
</a></li>
|
||||
<li @click="active=!active" class="option"style="float: right;" title=settings>
|
||||
<li @click="active=!active" class="option"style="float: right;" title=settings>
|
||||
<a class="icon" >
|
||||
<div class="fa-solid fa-gear" style="margin-top: 7px; margin-bottom: 3px;"></div>
|
||||
<div v-if="active" class="dropdown">
|
||||
@ -86,12 +86,9 @@ window.addEventListener('hashchange', () => {
|
||||
</ul>
|
||||
</div>
|
||||
<div class="page">
|
||||
<div style=" margin:50px;">
|
||||
<Suspense>
|
||||
|
||||
<component :is="currentView" />
|
||||
<component :is="currentView" />
|
||||
</Suspense>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -99,19 +96,22 @@ window.addEventListener('hashchange', () => {
|
||||
<style scoped>
|
||||
|
||||
.container{
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display:grid;
|
||||
grid-template-columns:[firstCol-start]70px[firstCol-end secondCol-start]auto[endCol];
|
||||
grid-template-rows:[firstRow-start]61px[firstRow-end secondRow-start] auto [endRow];
|
||||
|
||||
grid-template-columns:[firstCol-start]70px[firstCol-end secondCol-start] auto [endCol];
|
||||
grid-template-rows:[firstRow-start] var(--header-size) [firstRow-end secondRow-start] calc(100% - var(--header-size)) [endRow];
|
||||
grid-template-areas:
|
||||
"topBar topBar"
|
||||
"leftBar page";
|
||||
row-gap:0px;
|
||||
column-gap:0px;
|
||||
|
||||
}
|
||||
|
||||
.page {
|
||||
grid-area:page;
|
||||
place-self:center;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.topBar{
|
||||
@ -154,7 +154,7 @@ window.addEventListener('hashchange', () => {
|
||||
|
||||
ul.vertical{
|
||||
list-style-type: none;
|
||||
margin-top: 61px;
|
||||
margin-top: var(--header-size);
|
||||
top:0;
|
||||
left:0;
|
||||
padding: 25px 0 0;
|
||||
@ -202,7 +202,7 @@ window.addEventListener('hashchange', () => {
|
||||
left:0;
|
||||
|
||||
position: fixed;
|
||||
height:61px;
|
||||
height:var(--header-size);
|
||||
width: 100%;
|
||||
background-color: rgb(24, 24, 24);
|
||||
}
|
||||
|
138
frontend/src/Apps/Forums.vue
Normal file
138
frontend/src/Apps/Forums.vue
Normal file
@ -0,0 +1,138 @@
|
||||
<!----------------------------------------------------
|
||||
File: Forums.vue
|
||||
Author: Anthony Debucquoy
|
||||
Scope: Extension messagerie
|
||||
Description: Forum des étudiants
|
||||
----------------------------------------------------->
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from 'vue'
|
||||
import { getCourses } from '@/rest/courses.js'
|
||||
import { ForumsOfCurrentCourse, getForumsOfCourse } from '@/rest/forum.js'
|
||||
import { PostsOfCurrentForum, getPostsOfForum } from '@/rest/forum.js'
|
||||
import { fetchedPost, fetchPost } from '@/rest/forum.js'
|
||||
|
||||
const courses = await reactive(getCourses());
|
||||
const selectedCourse = ref();
|
||||
const selectedForum = ref();
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div id="app">
|
||||
<div id="ForumSelector">
|
||||
<select id="cours" value="" v-model="selectedCourse" @change="getForumsOfCourse(selectedCourse)">
|
||||
<option v-for="course in courses" :value="course.courseId">{{course.title}}</option>
|
||||
</select>
|
||||
|
||||
<select id="forum" value="" v-model="selectedForum" @change="getPostsOfForum(selectedForum)" v-if="ForumsOfCurrentCourse != null">
|
||||
<option v-for="forum in ForumsOfCurrentCourse" :value=forum.id>{{forum.name}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<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>
|
||||
<!--button id="createPost" @click="createPost()">+</button-->
|
||||
</div>
|
||||
<div id="PostViewer" v-if="fetchedPost != null">
|
||||
<div id="Post">
|
||||
<h1>{{ fetchedPost.subject }}</h1>
|
||||
{{fetchedPost.content}}
|
||||
</div>
|
||||
<div id="Messages">
|
||||
<p v-for="msg in fetchedPost.messages">{{msg.author}} - {{msg.content}}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
#app{
|
||||
display: grid;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
grid-template: 5em auto / 25% 75%;
|
||||
}
|
||||
|
||||
#ForumSelector{
|
||||
background-color: #FFFFFF0E;
|
||||
grid-column: 1 / 3;
|
||||
border-radius: 100px;
|
||||
margin: 10px;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
#ForumSelector select{
|
||||
background-color: #ffa000;
|
||||
border: none;
|
||||
margin: 10px;
|
||||
border-radius: 10px;
|
||||
width: 200px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#ForumSelector button{
|
||||
background-color: green;
|
||||
border: none;
|
||||
border-radius: 25%;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
#PostSelector{
|
||||
background-color: #FFFFFF0E;
|
||||
border-radius: 0 25px 25px 0;
|
||||
margin: 10px 0 10px 10px;
|
||||
overflow: hidden;
|
||||
padding: 10px;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
}
|
||||
|
||||
.postItem{
|
||||
color: darkorange;
|
||||
display: flex;
|
||||
font-family: sans-serif;
|
||||
font-weight: bold;
|
||||
height: 4vh;
|
||||
margin: 5px;
|
||||
border-radius: 0 30px 30px 0;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 1px solid darkorange;
|
||||
}
|
||||
|
||||
.postItem:hover{
|
||||
background-color: gray;
|
||||
}
|
||||
|
||||
#PostViewer{
|
||||
background-color: #FFFFFF0E;
|
||||
border-radius: 25px;
|
||||
margin: 10px;
|
||||
|
||||
max-height: 100%;
|
||||
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
#Post{
|
||||
padding: 25px;
|
||||
|
||||
}
|
||||
|
||||
#Messages{
|
||||
padding: 25px;
|
||||
border-top: 3px dotted white;
|
||||
|
||||
}
|
||||
|
||||
#Messages > p {
|
||||
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
@ -16,10 +16,9 @@
|
||||
|
||||
|
||||
<template>
|
||||
<div v-for="item of requests">
|
||||
<div style='display:flex; justify-content:center; min-width:1140px;' v-for="item of requests">
|
||||
<div class="bodu" v-if="item.state === 'Pending'">
|
||||
<div class="container">
|
||||
|
||||
<div class="id"><a>{{item.id}}</a></div>
|
||||
<div class="surname"><a>{{item.lastName}}</a></div>
|
||||
<div class="firstname"><a>{{item.firstName}}</a></div>
|
||||
@ -37,10 +36,9 @@
|
||||
height:100px;
|
||||
font-size:20px;
|
||||
display:grid;
|
||||
grid-template-columns:[firstCol-start]100px[firstCol-end secondCol-start]150px[secondCol-end thirdCol-start]200px[thirdCol-end fourthCol-start]150px[fourthCol-end]150px[fifthCol-end]150px[sixthCol-end]150px[endCol];
|
||||
grid-template-columns:10% 14.2% 19% 14.2% 14.2% 14.2% 14.2%;
|
||||
grid-template-areas:
|
||||
"id type surname firstname infos accept refuse";
|
||||
column-gap:10px;
|
||||
|
||||
}
|
||||
|
||||
@ -99,9 +97,9 @@
|
||||
|
||||
}
|
||||
|
||||
.bodu {
|
||||
width:100%;
|
||||
margin-bottom:10px;
|
||||
.bodu {
|
||||
margin-top:2%;
|
||||
width:66%;
|
||||
border:2px solid black;
|
||||
border-radius:9px;
|
||||
background-color:rgb(50,50,50);
|
||||
|
@ -56,10 +56,10 @@
|
||||
|
||||
|
||||
<template>
|
||||
<div class='loginBox'>
|
||||
|
||||
<div class="setup">
|
||||
<div v-if="loginPage">
|
||||
<form @submit.prevent=" login(outputs.email,outputs.password);goBackHome();"class="form">
|
||||
<div class='loginBox' style="margin-top:30%;">
|
||||
<form @submit.prevent="login(outputs.email,outputs.password);goBackHome();"class="form">
|
||||
<h1 style="color:rgb(239,60,168); font-family: sans-serif;">
|
||||
{{i18n("login.guest.signin")}}
|
||||
</h1>
|
||||
@ -74,14 +74,15 @@
|
||||
<div class="register">
|
||||
<a @click="loginPage=!loginPage">{{i18n("login.guest.register")}}</a>
|
||||
</div>
|
||||
<div class="inputBox">
|
||||
<div class="inputBox" style="margin-bottom:35px;">
|
||||
<input type="submit" v-model="submitValue">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div v-else>
|
||||
<form class="form">
|
||||
<div class='loginBox' style="margin-top:30%; margin-bottom:50%;">
|
||||
<form class="form">
|
||||
<h1 style="color:rgb(239,60,168); font-family: sans-serif; text-align:center;">
|
||||
{{i18n("login.guest.welcome")}}
|
||||
</h1>
|
||||
@ -128,9 +129,12 @@
|
||||
<p>{{i18n("login.guest.country")}}</p>
|
||||
<input type="text" v-model="outputs.country">
|
||||
</div>
|
||||
<form novalidate enctype="multipart/form-data" class="inputBox">
|
||||
<form class="inputBox"novalidate enctype="multipart/form-data">
|
||||
<p>{{i18n("profile.picture").toUpperCase()}}</p>
|
||||
<input type="file" :disabled="imageSaved" @change="ppData = uploadProfilePicture($event.target.files); imageSaved = true;" accept="image/*">
|
||||
<label class="browser">
|
||||
Parcourir . . .
|
||||
<input type="file" :disabled="imageSaved" @change="ppData = uploadProfilePicture($event.target.files); imageSaved = true;" accept="image/*">
|
||||
</label>
|
||||
</form>
|
||||
<div class="inputBox">
|
||||
<p>{{i18n("Curriculum").toUpperCase()}}</p>
|
||||
@ -153,35 +157,26 @@
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.Home{
|
||||
position:absolute;
|
||||
display: flex;
|
||||
z-index: 100;
|
||||
padding: 8px 16px;
|
||||
color:rgb(255, 255, 255);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.Home:hover{
|
||||
width:40px;
|
||||
background-color: black;
|
||||
border-radius:6px;
|
||||
color:white;
|
||||
transform: translate(0px ,1px);
|
||||
}
|
||||
.setup {
|
||||
margin-left: auto;
|
||||
margin-right:auto;
|
||||
min-width:400px;
|
||||
|
||||
width:25%;
|
||||
height:60%;
|
||||
}
|
||||
|
||||
.loginBox {
|
||||
background-color: rgb(24,24,24);
|
||||
width: 400px;
|
||||
display:flex;
|
||||
justify-content: center;
|
||||
padding: 40px;
|
||||
border-radius: 20px;
|
||||
border-radius: 5%;
|
||||
box-shadow:0 5px 25px #000000;
|
||||
|
||||
}
|
||||
@ -190,9 +185,8 @@
|
||||
width:100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items:center;
|
||||
gap: 15px;
|
||||
gap: 3%;
|
||||
}
|
||||
|
||||
|
||||
@ -200,12 +194,12 @@
|
||||
|
||||
width:100%;
|
||||
border: none;
|
||||
margin-right: 50px;
|
||||
padding-left: 10px;
|
||||
padding-top:10px;
|
||||
padding-bottom:10px;
|
||||
margin-right: 12.5%;
|
||||
padding-left: 2.5%;
|
||||
padding-top:2.5%;
|
||||
padding-bottom:2.5%;
|
||||
outline:none;
|
||||
border-radius: 4px;
|
||||
border-radius: 10px;
|
||||
font-size:1.35em;
|
||||
}
|
||||
|
||||
@ -220,8 +214,9 @@
|
||||
|
||||
.register{
|
||||
color:rgb(239,60,168);
|
||||
width: 100%;
|
||||
display:flex;
|
||||
width:70%;
|
||||
margin-bottom:20px;
|
||||
margin-top:20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@ -250,6 +245,21 @@ input[type=submit],button,select{
|
||||
|
||||
}
|
||||
|
||||
input[type=file]{
|
||||
display:none;
|
||||
}
|
||||
|
||||
.browser{
|
||||
display:inline-block;
|
||||
cursor:pointer;
|
||||
border-radius:20px;
|
||||
background-color:rgb(239,60,168);
|
||||
padding:5%;
|
||||
font-size:1.35em;
|
||||
font-family:sans-serif;
|
||||
background:#FFFFFF;
|
||||
}
|
||||
|
||||
button:active ,.switchpage:active{
|
||||
opacity:0.8;
|
||||
|
||||
|
@ -105,7 +105,8 @@
|
||||
</button>
|
||||
</div>
|
||||
<div v-if="createMod">
|
||||
<form class="listElement">
|
||||
<form class="listElement" style="width:40%;margin-right:auto;margin-left:auto;">
|
||||
|
||||
<div style="margin-bottom:20px;">
|
||||
{{i18n("name")}} :
|
||||
<input v-model="toAdd.title">
|
||||
@ -125,7 +126,7 @@
|
||||
</form>
|
||||
</div>
|
||||
<div v-if="deleteMod">
|
||||
<form class="listElement">
|
||||
<form class="listElement" style="width:40%;margin-right:auto;margin-left:auto;">
|
||||
<div style="margin-bottom:20px;">
|
||||
{{i18n("courses.toDelete")}} :
|
||||
<select style="max-width:200px;" class="teacher" v-model="toRemove">
|
||||
@ -138,7 +139,7 @@
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div v-if="!createMod && !deleteMod" v-for="item in curriculum" :key="item.title">
|
||||
<div v-if="!createMod && !deleteMod" v-for="item in curriculum" :key="item.title" style="width:50%;margin-left:auto; margin-right:auto;">
|
||||
<div v-if="editElementID !== item.title" style ="padding:15px 15px 15px 15px;">
|
||||
<button @click="editElementID = item.title; setModify(item); ">
|
||||
{{i18n("courses.modify")}}
|
||||
@ -149,6 +150,7 @@
|
||||
<button @click="editElementID= '';"> {{i18n("courses.back")}} </button>
|
||||
</div>
|
||||
<div class="listElement" >
|
||||
|
||||
<div class="containerElement" v-if="editElementID !== item.title" >
|
||||
|
||||
<div class="name"> {{item.title}} </div>
|
||||
@ -172,17 +174,27 @@
|
||||
<style scoped>
|
||||
.body {
|
||||
width:100%;
|
||||
margin-bottom:10px;
|
||||
margin-top:3.5%;
|
||||
}
|
||||
|
||||
.infosContainer {
|
||||
min-width:350px;
|
||||
padding-bottom:50px;
|
||||
border:2px solid black;
|
||||
font-size:25px;
|
||||
color:white;
|
||||
padding:20px;
|
||||
background-color:rgb(50,50,50);
|
||||
border-radius:20px;
|
||||
}
|
||||
|
||||
.containerElement{
|
||||
justify-content:center;
|
||||
justify-content:center;
|
||||
display:grid;
|
||||
grid-template-columns:350px 350px 200px;
|
||||
grid-template-columns:38.8% 38.8% 22.4%;
|
||||
grid-template-areas:
|
||||
"name teacher credits";
|
||||
column-gap:10px;
|
||||
|
||||
}
|
||||
column-gap:10px; }
|
||||
|
||||
.name {
|
||||
grid-area:name;
|
||||
@ -200,6 +212,7 @@
|
||||
}
|
||||
|
||||
.listElement{
|
||||
min-width:625px;
|
||||
border:2px solid black;
|
||||
font-size:25px;
|
||||
color:white;
|
||||
@ -207,6 +220,7 @@
|
||||
background-color:rgb(50,50,50);
|
||||
border-radius:20px;
|
||||
margin-bottom:10px;
|
||||
|
||||
}
|
||||
|
||||
.modify{
|
||||
@ -255,10 +269,11 @@
|
||||
}
|
||||
|
||||
.listTitle{
|
||||
min-width:380px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width:400px;
|
||||
width:25%;
|
||||
margin-left:auto;
|
||||
margin-right:auto;
|
||||
border:2px solid black;
|
||||
@ -266,7 +281,8 @@
|
||||
color:white;
|
||||
padding:20px;
|
||||
background-color:rgb(50,50,50);
|
||||
border-radius:20px;margin-bottom:10px;
|
||||
border-radius:20px;
|
||||
margin-bottom:10px;
|
||||
|
||||
button:hover{
|
||||
opacity:0.8;
|
||||
|
@ -210,11 +210,11 @@
|
||||
<style scoped>
|
||||
|
||||
.container{
|
||||
|
||||
min-width:675px;
|
||||
display:grid;
|
||||
grid-template-columns:200px 900px;
|
||||
grid-template-columns:10vw 50vw;
|
||||
grid-template-rows:200px auto;
|
||||
column-gap:30px;
|
||||
column-gap:2.7%;
|
||||
row-gap:45px;
|
||||
grid-template-areas:
|
||||
"profilPic globalInfos"
|
||||
@ -222,6 +222,7 @@
|
||||
}
|
||||
|
||||
.profilPic{
|
||||
width:100%;
|
||||
grid-area:profilPic;
|
||||
}
|
||||
|
||||
@ -242,13 +243,17 @@
|
||||
grid-area:minfos;
|
||||
}
|
||||
.body {
|
||||
min-width:960px;
|
||||
width:100%;
|
||||
margin-bottom:10px;
|
||||
display:flex;
|
||||
align-items:center;
|
||||
justify-content:center;
|
||||
margin-top:5%;
|
||||
}
|
||||
.containerElement{
|
||||
justify-content:center;
|
||||
display:grid;
|
||||
grid-template-columns:350px 350px 200px;
|
||||
grid-template-columns:38.8% 38.8% 22.4%;
|
||||
grid-template-areas:
|
||||
"name teacher credits";
|
||||
column-gap:10px;
|
||||
@ -271,10 +276,11 @@
|
||||
}
|
||||
|
||||
.listTitle{
|
||||
min-width:197px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width:200px;
|
||||
width:8vw;
|
||||
margin-left:auto;
|
||||
margin-right:auto;
|
||||
border:2px solid black;
|
||||
@ -286,6 +292,7 @@
|
||||
}
|
||||
|
||||
.listElement{
|
||||
min-width:625px;
|
||||
border:2px solid black;
|
||||
font-size:25px;
|
||||
color:white;
|
||||
@ -296,6 +303,7 @@
|
||||
}
|
||||
|
||||
.infosContainer {
|
||||
min-width:350px;
|
||||
padding-bottom:50px;
|
||||
border:2px solid black;
|
||||
font-size:25px;
|
||||
|
@ -5,8 +5,8 @@
|
||||
|
||||
const users = await getStudents();
|
||||
</script>
|
||||
<template>
|
||||
<div v-for="item in users">
|
||||
<template style="margin-top:5%;">
|
||||
<div style="display:flex; justify-content:center; " v-for="item in users">
|
||||
<div class="bodu">
|
||||
<div class="container">
|
||||
<div class="status"><a style="margin-left:30px">{{item.status}}</a></div>
|
||||
@ -25,10 +25,9 @@
|
||||
height:100px;
|
||||
font-size:30px;
|
||||
display:grid;
|
||||
grid-template-columns:250px 250px 250px 250px 150px;
|
||||
grid-template-columns:21.7% 21.7% 21.7% 21.7% 13.1%;
|
||||
grid-template-areas:
|
||||
"status option surname firstname infos";
|
||||
column-gap:10px;
|
||||
|
||||
}
|
||||
|
||||
@ -42,21 +41,6 @@
|
||||
align-self:center;
|
||||
}
|
||||
|
||||
.refuse{
|
||||
grid-area:refuse;
|
||||
align-self:center;
|
||||
}
|
||||
|
||||
.titles {
|
||||
grid-area:titles;
|
||||
background-color:rgb(215,215,215);
|
||||
}
|
||||
.id{
|
||||
grid-area:id;
|
||||
margin-left:40px;
|
||||
align-self:center;
|
||||
}
|
||||
|
||||
.status{
|
||||
grid-area:status;
|
||||
align-self:center;
|
||||
@ -81,15 +65,15 @@
|
||||
button{
|
||||
font-size:15px;
|
||||
height:50px;
|
||||
width:100px;
|
||||
width:75%;
|
||||
border:none;
|
||||
border-radius:20px;
|
||||
|
||||
}
|
||||
|
||||
.bodu {
|
||||
width:100%;
|
||||
margin-bottom:10px;
|
||||
margin-top:2%;
|
||||
width:66%;
|
||||
border:2px solid black;
|
||||
border-radius:9px;
|
||||
background-color:rgb(50,50,50);
|
||||
|
@ -7,8 +7,8 @@
|
||||
const users = await getAllUsers();
|
||||
|
||||
</script>
|
||||
<template>
|
||||
<div v-for="item in users">
|
||||
<template style="margin-top:5%;">
|
||||
<div style="display:flex; justify-content:center; min-width:1140px;" v-for="item in users">
|
||||
<div class="bodu">
|
||||
<div class="container">
|
||||
<div class="role"><a style="margin-left:30px">{{i18n(item.role)}}</a></div>
|
||||
@ -22,23 +22,20 @@
|
||||
|
||||
<style scoped>
|
||||
.container{
|
||||
justify-content:center;
|
||||
align-items:center;
|
||||
color:white;
|
||||
height:100px;
|
||||
font-size:30px;
|
||||
display:grid;
|
||||
grid-template-columns:250px 250px 250px 150px;
|
||||
grid-template-columns:27.7% 27.7% 27.7% 16.9%;
|
||||
grid-template-areas:
|
||||
"role surname firstname infos";
|
||||
column-gap:10px;
|
||||
|
||||
}
|
||||
|
||||
.infos {
|
||||
|
||||
grid-area:infos;
|
||||
align-items:center;
|
||||
align-self:center;
|
||||
}
|
||||
|
||||
.role {
|
||||
@ -67,20 +64,18 @@
|
||||
button{
|
||||
font-size:15px;
|
||||
height:50px;
|
||||
width:100px;
|
||||
width:75%;
|
||||
border:none;
|
||||
border-radius:20px;
|
||||
|
||||
}
|
||||
|
||||
.bodu {
|
||||
width:100%;
|
||||
margin-bottom:10px;
|
||||
margin-top:2%;
|
||||
width:66%;
|
||||
border:2px solid black;
|
||||
border-radius:9px;
|
||||
background-color:rgb(50,50,50);
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
|
@ -1,4 +1,15 @@
|
||||
:root {
|
||||
--header-size: 61px;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: rgb(53, 25, 60);
|
||||
margin:0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
#app {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import Profil from "@/Apps/Profil.vue"
|
||||
import Courses from "@/Apps/ManageCourses.vue"
|
||||
import Users from "@/Apps/UsersList.vue"
|
||||
import Students from "@/Apps/StudentsList.vue"
|
||||
import Forums from '@/Apps/Forums.vue'
|
||||
|
||||
const apps = {
|
||||
'/login': LoginPage,
|
||||
@ -17,12 +18,13 @@ const apps = {
|
||||
'/manage-courses' : Courses,
|
||||
'/users-list' : Users,
|
||||
'/students-list' : Students,
|
||||
'/forums': Forums,
|
||||
}
|
||||
|
||||
const appsList = {
|
||||
'Msg': { path: '#/msg', icon: 'fa-comment', text: i18n("app.messages") },
|
||||
'Notification': { path: '#/notifs', icon: 'fa-bell', text: i18n("app.notifications") },
|
||||
'Forum': { path: '#/forum', icon: 'fa-envelope', text: i18n("app.forum") },
|
||||
'Forum': { path: '#/forums', icon: 'fa-envelope', text: i18n("app.forum") },
|
||||
'Schedule': { path: '#/schedule', icon: 'fa-calendar-days', text: i18n("app.schedules") },
|
||||
'Inscription': { path: '#/inscription', icon: 'fa-users', text: i18n("app.inscription.requests") },
|
||||
'ManageCourses': { path: '#/manage-courses', icon: 'fa-book', text: i18n("app.manage.courses") },
|
||||
|
71
frontend/src/rest/forum.js
Normal file
71
frontend/src/rest/forum.js
Normal file
@ -0,0 +1,71 @@
|
||||
import { ref } from 'vue'
|
||||
import { restGet, restPost, restDelete, restPatch } from './restConsumer.js'
|
||||
|
||||
/**
|
||||
* List forums of a course
|
||||
*/
|
||||
export async function getForumsOfCourse(id){
|
||||
ForumsOfCurrentCourse.value = [
|
||||
{
|
||||
id: 1,
|
||||
name: "forum~1"
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "forum~2"
|
||||
},
|
||||
]
|
||||
// ForumsOfCurrentCourse = await restGet("/forums/" + id)
|
||||
}
|
||||
|
||||
export const ForumsOfCurrentCourse = ref();
|
||||
|
||||
/**
|
||||
* List post of a specified forum
|
||||
*/
|
||||
export async function getPostsOfForum(id){
|
||||
PostsOfCurrentForum.value = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Post~1"
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "Post~2"
|
||||
},
|
||||
]
|
||||
// PostsCurrentForum.value = await restGet("/forum/" + id);
|
||||
}
|
||||
|
||||
export const PostsOfCurrentForum = ref();
|
||||
|
||||
/**
|
||||
* Get a post and its responses
|
||||
*/
|
||||
export async function fetchPost(id){
|
||||
fetchedPost.value = {
|
||||
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..."
|
||||
}
|
||||
]
|
||||
}
|
||||
// fetchedPost.value = await restGet("/forum/post/" + id);
|
||||
}
|
||||
|
||||
export const fetchedPost = ref();
|
Reference in New Issue
Block a user