diff --git a/.gitignore b/.gitignore index d1daeb8e..257611f6 100644 --- a/.gitignore +++ b/.gitignore @@ -145,3 +145,5 @@ Desktop.ini # ESLint ###################### .eslintcache + +danenv/ \ No newline at end of file diff --git a/README.md b/README.md index 9754a681..c1939017 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,14 @@ -# correctExamBack +# CorrectExam back-end -Deliver and Grade Your Assessments Anywhere +The back-end of the app CorrectExam. + +## CorrectExam + +**Deliver and Grade Your Assessments Anywhere** This application helps you seamlessly administer and grade all of your in-class assessments (long exam or short). Save time grading and get a clear picture of how your students are doing. Provide a clear feedback to your students. -# Feature +### Feature Main feature are: @@ -15,29 +19,65 @@ Main feature are: - use your tablet and your pen to annotate student sheet - provide clear feedback to your students -# Technical stack +### Technical stack This application was generated using JHipster 6.10.5 and JHipster Quarkus 1.1.1 (manually upgraded to quarkus 2.9.2.Final), you can find documentation and help at [https://www.jhipster.tech/documentation-archive/v6.10.5](https://www.jhipster.tech/documentation-archive/v6.10.5). -## Build and deploy +### Build and deploy -Documenttion to deploy your own instance is available [here](https://correctexam.readthedocs.io/en/latest/Install.html) +Documentation to deploy your own instance is available [here](https://correctexam.readthedocs.io/en/latest/Install.html) ## Development -To start your application in the dev profile, run: +### Install + +The back-end requires Minio to store the PDF files. +An easy way to install and launch Minio on your computer is to use an official Docker image: + +``` +podman run -p 9000:9000 -d -p 9090:9090 -e "MINIO_ROOT_USER=admin" -e "MINIO_ROOT_PASSWORD=minioadmin" -v /media/data/miniofiles:/data:Z quay.io/minio/minio server /data --console-address ":9090" +``` + +The back-end also requires a database. +On Linux you can install MariaDB. +On Fedora, you can run: + +``` +sudo dnf install mariadb-server +sudo systemctl enable mariadb +sudo systemctl start mariadb +sudo mysql_secure_installation + +sudo mysql -u root +CREATE DATABASE gradeScopeIstic; +``` + +The first run of the back-end must initial and populate the DB with fake data. To do so, run: +``` +./mvnw quarkus:dev -Dquarkus.liquibase.migrate-at-start=true +``` + +It creates two users `user:user` and `admin:admin`. +After that you can launch the back-end classically `./mvnw` - ./mvnw + +### Run in development mode + +To start your application in the dev profile, run: + +``` +./mvnw +``` For further instructions on how to develop with JHipster, have a look at [Using JHipster in development][]. -## Building for production +### Building for production -### Packaging as thin jar +#### Packaging as thin jar To build the final jar and optimize the correctExam application for production, run: @@ -51,7 +91,7 @@ To ensure everything worked, run: Refer to [Using JHipster in production][] for more details. -### Packaging as native executable +#### Packaging as native executable _Targeting your Operation System_ In order to build a native image locally, your need to have [GraalVM](https://www.graalvm.org/) installed and `GRAALVM_HOME` defined. @@ -72,7 +112,7 @@ If you plan to run your application in a container, run: It will use a Docker container with GraalVM installed and produce an 64 bit Linux executable. -## Testing +### Testing To launch your application's tests, run: @@ -80,7 +120,7 @@ To launch your application's tests, run: For more information, refer to the [Running tests page][]. -## Using Docker to simplify development (optional) +### Using Docker to simplify development (optional) You can use Docker to improve your JHipster development experience. A number of docker-compose configuration are available in the [src/main/docker](src/main/docker) folder to launch required third party services. @@ -103,66 +143,14 @@ To stop it and remove the container, run: -update question set point = point * 4; - -update `student_response` set note = note * 4; -ALTER TABLE `question` ADD `libelle` VARCHAR(255) NULL DEFAULT NULL AFTER `valid_expression`; -ALTER TABLE `gradeScopeIstic`.`final_result` ADD UNIQUE `UniqueStudentIdAndExamId` (`student_id`, `exam_id`); - - -create table answer_2_hybrid_graded_comment (id bigint not null auto_increment, step_value integer, hybridcomments_id bigint, student_response_id bigint, primary key (id)) engine=InnoDB; -create table hybrid_graded_comment (id bigint not null auto_increment, description longtext, grade integer, relative bit, step integer, text varchar(255), question_id bigint, primary key (id)) engine=InnoDB; - - -alter table final_result add column frozen bit; -alter table question add column defaultpoint integer; -alter table answer_2_hybrid_graded_comment add constraint FK9ijm3itpjwpgf534m94df8dt6 foreign key (hybridcomments_id) references hybrid_graded_comment (id); -alter table answer_2_hybrid_graded_comment add constraint FKqxflsw40s622dtyt99himou2k foreign key (student_response_id) references student_response (id); -alter table hybrid_graded_comment add constraint FKrrl2y7dngtnqlklwt0scsy8jq foreign key (question_id) references question (id); - -ALTER TABLE `gradeScopeIstic`.`answer_2_hybrid_graded_comment` ADD UNIQUE `UniqueHybridcommentsIdAndStudentResponseId` (`student_response_id`, `hybridcomments_id`); - -ALTER TABLE `student_response` ADD UNIQUE(`question_id`, `sheet_id`); - - -alter table student_response add column lastmodified datetime(6); -alter table student_response add column correctedby_id bigint; -alter table student_response add constraint FKinrpshecm7c6aiqo6000ju87c foreign key (correctedby_id) references jhi_user (id); - -alter table question add column randomhorizontalcorrection bit default 0; - - - -[x] unique constraint for answer_2_hybrid_graded_comment -[x] delete correctly when removing exam or course -[x] Import Export with HybridComment -[x] Test import and export -[x] check delete -[x] Export PDF with HybridComment - -[x] update question or hybridComment => recompute score4 linked StudentResponse -[x] test update question or hybridComment => recompute score4 linked StudentResponse -[x] update maximal step from 5 to 12. -[x] Allow direct grading when clicking to star -[x] Update view copie4student -[x] update show all with this hybridComment -[x] update apply to all the same grade - - - - SELECT resp.id FROM `student_response` as resp WHERE EXISTS( SELECT * FROM `student_response` as resp2 WHERE resp.id <> resp2.id and resp.question_id = resp2.question_id and resp.sheet_id = resp2.sheet_id); - -select * from student_response_textcomments as st3 where st3.student_response_id IN( - SELECT resp.id FROM `student_response` as resp WHERE EXISTS( SELECT * FROM `student_response` as resp2 WHERE resp.id <> resp2.id and resp.question_id = resp2.question_id and resp.sheet_id = resp2.sheet_id)); - +-- upgrade database script -DELETE from answer_2_hybrid_graded_comment as an where an.student_response_id IN( - SELECT resp.id FROM `student_response` as resp WHERE EXISTS( SELECT * FROM `student_response` as resp2 WHERE resp.id <> resp2.id and resp.question_id = resp2.question_id and resp.sheet_id = resp2.sheet_id)); +create table prediction (id bigint not null auto_increment, json_data tinytext, confidence float(53), question_number varchar(255), text varchar(2048), question_id bigint, sheet_id bigint, primary key (id)); +alter table template add column casename bit DEFAULT 1; +alter table course add column archived bit not null DEFAULT 0; -select an.* from answer_2_hybrid_graded_comment as an where an.student_response_id IN(SELECT resp.id FROM `student_response` as resp WHERE EXISTS( SELECT * FROM `student_response` as resp2 WHERE resp.id <> resp2.id and resp.question_id = resp2.question_id and resp.sheet_id = resp2.sheet_id)); -delete an.* from answer_2_hybrid_graded_comment as an where an.student_response_id IN( - SELECT resp.id FROM `student_response` as resp WHERE EXISTS( SELECT * FROM `student_response` as resp2 WHERE resp.id <> resp2.id and resp.question_id = resp2.question_id and resp.sheet_id = resp2.sheet_id)); +alter table prediction add constraint FK1xsmwx00gk7213kwfeah9lcjx foreign key (question_id) references question (id); +alter table prediction add constraint FK8nv2hkm3mhxll6be9mwj5402t foreign key (sheet_id) references exam_sheet (id); - DELETE FROM `student_response` WHERE id in (53044,53045,53046,53047,53050,53051,53052,53053,53054,53055,53056,53057,53058,53059,53061,53062,53063,53064,53065,53066,53067,53068,53106,53107,53108,53109,53110,53111,53112,53113,53114,53115,53117,53118,53119,53120,53121,53122,53124,53125,53126,53127,53128,53129,53130,53131,53133,53134,53135,53136,53184,53185,53240,53241,53242,53243,53244,53245,53248,53249,53250,53251); diff --git a/pom.xml b/pom.xml index a30a1c5f..7cfdfbb6 100644 --- a/pom.xml +++ b/pom.xml @@ -57,8 +57,6 @@ - - org.apache.pdfbox pdfbox diff --git a/src/main/docker/app.yml b/src/main/docker/app.yml index 99ecb789..f3d8b15e 100644 --- a/src/main/docker/app.yml +++ b/src/main/docker/app.yml @@ -23,6 +23,18 @@ services: file: mysql.yml service: correctexam-mysql +#To activate to setup rag + +# correctexam-es: +# extends: +# file: es.yml +# service: correctexam-es + +# correctexam-kibana: +# extends: +# file: es.yml +# service: correctexam-kibana + front: image: barais/correctexam-front build: @@ -67,3 +79,8 @@ services: volumes: - ./exampleconf/smtprelay.ini:/app/smtprelay.ini:ro - ./tmp:/tmp:rw + +# To activate to setup rag + +#networks: +# elastic: diff --git a/src/main/docker/es.yml b/src/main/docker/es.yml new file mode 100644 index 00000000..9687954f --- /dev/null +++ b/src/main/docker/es.yml @@ -0,0 +1,35 @@ +version: '1' +services: + correctexam-es: + image: elasticsearch:8.8.0 + ports: + - 9200:9200 + - 9300:9300 + networks: + - elastic + environment: + - discovery.type=single-node + - xpack.security.enabled=false + - "ES_JAVA_OPTS=-Xms512m -Xmx2048m" + - cluster.routing.allocation.disk.threshold_enabled=false + deploy: + resources: + limits: + cpus: '2.0' + reservations: + cpus: '1.0' + correctexam-kibana: + image: docker.elastic.co/kibana/kibana:8.7.1 + container_name: kibana + environment: + XPACK_ENCRYPTEDSAVEDOBJECTS_ENCRYPTIONKEY: d1a66dfd-c4d3-4a0a-8290-2abcb83ab3aa + ports: + - 5601:5601 + networks: + - elastic + deploy: + resources: + limits: + cpus: '2.0' + reservations: + cpus: '1.0' \ No newline at end of file diff --git a/src/main/docker/k8s/correctexam-mysql-claim0-persistentvolumeclaim.yaml b/src/main/docker/k8s/correctexam-mysql-claim0-persistentvolumeclaim.yaml index dee41144..13e0a1bc 100644 --- a/src/main/docker/k8s/correctexam-mysql-claim0-persistentvolumeclaim.yaml +++ b/src/main/docker/k8s/correctexam-mysql-claim0-persistentvolumeclaim.yaml @@ -344,7 +344,8 @@ data: INSERT INTO `question_type` (`id`, `algo_name`, `endpoint`, `js_function`) VALUES (2, 'manual', '', ''), - (3, 'QCM', NULL, NULL); + (3, 'QCM', NULL, NULL), + (4, 'manuscrit', '', ''); -- -------------------------------------------------------- diff --git a/src/main/java/fr/istic/domain/Course.java b/src/main/java/fr/istic/domain/Course.java index f1af2400..9bfea3eb 100644 --- a/src/main/java/fr/istic/domain/Course.java +++ b/src/main/java/fr/istic/domain/Course.java @@ -34,6 +34,11 @@ public class Course extends PanacheEntityBase implements Serializable { @Column(name = "name", nullable = false) public String name; + @NotNull + @Column(name = "archived", nullable = false) + public Boolean archived = false; + + @OneToMany(mappedBy = "course", cascade = CascadeType.REMOVE, fetch = FetchType.LAZY) @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) public Set exams = new HashSet<>(); @@ -92,6 +97,7 @@ public static Course update(Course course) { var entity = Course.findById(course.id); if (entity != null) { entity.name = course.name; + entity.archived = course.archived; entity.exams = course.exams; entity.groups = course.groups; entity.profs = course.profs; diff --git a/src/main/java/fr/istic/domain/Exam.java b/src/main/java/fr/istic/domain/Exam.java index 095b1786..3ab625ad 100644 --- a/src/main/java/fr/istic/domain/Exam.java +++ b/src/main/java/fr/istic/domain/Exam.java @@ -3,8 +3,6 @@ import jakarta.json.bind.annotation.JsonbTransient; import io.quarkus.hibernate.orm.panache.PanacheQuery; import io.quarkus.runtime.annotations.RegisterForReflection; -import org.hibernate.annotations.Cache; -import org.hibernate.annotations.CacheConcurrencyStrategy; import jakarta.persistence.*; import jakarta.transaction.Transactional; @@ -33,6 +31,8 @@ public class Exam extends PanacheEntityBase implements Serializable { @Column(name = "name", nullable = false) public String name; + + @OneToOne(cascade = CascadeType.REMOVE) @JoinColumn(unique = true) public Template template; diff --git a/src/main/java/fr/istic/domain/ExamSheet.java b/src/main/java/fr/istic/domain/ExamSheet.java index 534caa24..11f10ec2 100644 --- a/src/main/java/fr/istic/domain/ExamSheet.java +++ b/src/main/java/fr/istic/domain/ExamSheet.java @@ -49,6 +49,11 @@ public class ExamSheet extends PanacheEntityBase implements Serializable { @JsonbTransient public Set students = new HashSet<>(); + + @OneToMany(mappedBy = "sheet") + @JsonbTransient + public Set predictions ; + // jhipster-needle-entity-add-field - JHipster will add fields here, do not remove @Override diff --git a/src/main/java/fr/istic/domain/Prediction.java b/src/main/java/fr/istic/domain/Prediction.java new file mode 100644 index 00000000..4c8a618b --- /dev/null +++ b/src/main/java/fr/istic/domain/Prediction.java @@ -0,0 +1,147 @@ +package fr.istic.domain; + +import io.quarkus.hibernate.orm.panache.PanacheEntityBase; +import io.quarkus.hibernate.orm.panache.PanacheQuery; +import jakarta.json.bind.annotation.JsonbTransient; +import io.quarkus.runtime.annotations.RegisterForReflection; + +import jakarta.persistence.*; +import java.io.Serializable; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * A Prediction. + */ +@Entity +@Table(name = "prediction") +@RegisterForReflection +public class Prediction extends PanacheEntityBase implements Serializable { + + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + public Long id; + + @Column(name = "text") + public String text; + + @Lob + @Column(name = "json_data") + public String jsonData; + + @Column(name = "question_number") + public String questionNumber; + + @Column(name = "confidence") + public double predictionconfidence; + + + + @ManyToOne + @JoinColumn(name = "question_id") + @JsonbTransient + public Question question; + + @ManyToOne + @JoinColumn(name = "sheet_id") + @JsonbTransient + public ExamSheet sheet; + + // jhipster-needle-entity-add-field - JHipster will add fields here, do not remove + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof Prediction)) { + return false; + } + return id != null && id.equals(((Prediction) o).id); + } + + @Override + public int hashCode() { + return 31; + } + + @Override + public String toString() { + return "Prediction{" + + "id=" + id + + ", text='" + text + "'" + + ", jsonData='" + jsonData + "'" + + ", predictionconfidence='" + predictionconfidence + "'" + + ", questionNumber='" + questionNumber + "'" + + "}"; + } + + public Prediction update() { + return update(this); + } + + public Prediction persistOrUpdate() { + return persistOrUpdate(this); + } + + public static Prediction update(Prediction prediction) { + if (prediction == null) { + throw new IllegalArgumentException("prediction can't be null"); + } + var entity = Prediction.findById(prediction.id); + if (entity != null) { + entity.text = prediction.text; + entity.jsonData = prediction.jsonData; + entity.predictionconfidence = prediction.predictionconfidence; + entity.questionNumber = prediction.questionNumber; + entity.question = prediction.question; + entity.sheet = prediction.sheet; + } + return entity; + } + + public static Prediction persistOrUpdate(Prediction prediction) { + if (prediction == null) { + throw new IllegalArgumentException("prediction can't be null"); + } + if (prediction.id == null) { + persist(prediction); + return prediction; + } else { + return update(prediction); + } + } + + public static PanacheQuery findByQuestionId(long qid) { + return find("select prediction from Prediction prediction where prediction.question.id = ?1", qid); + } + + public static long deleteByQIds(Set qids) { + return delete("delete from Prediction pr where pr.question.id in ?1", qids); + } + + public static long deleteByQId(Long qid) { + return delete("delete from Prediction pr where pr.question.id = ?1", qid); + } + + + public static PanacheQuery canAccess(long predictionId, String login) { + return find("select pr from Prediction pr join pr.question.exam.course.profs as u where pr.id = ?1 and u.login = ?2", predictionId, login); + } + + public static PanacheQuery findPredictionWithoutStudentResponse(List predictionIds) { + + + return find("select sr from StudentResponse as sr, from Prediction pr join pr.question.exam.question as q1 join q1.studentresponses as sr where q1.numero = pr.question.numero and sr.sheet. in ?1 and pr.question.studentResponse is null", predictionIds); + } + + public static PanacheQuery findStudentResponseWithoutStudentResponse(List predictionIds) { + + + return find("select sr from StudentResponse as sr, from Prediction pr join pr.question.exam.question as q1 join q1.studentresponses as sr where q1.numero = pr.question.numero and sr.sheet. in ?1 and pr.question.studentResponse is null", predictionIds); + } + +} diff --git a/src/main/java/fr/istic/domain/StudentResponse.java b/src/main/java/fr/istic/domain/StudentResponse.java index 96cd330a..ff184176 100644 --- a/src/main/java/fr/istic/domain/StudentResponse.java +++ b/src/main/java/fr/istic/domain/StudentResponse.java @@ -13,6 +13,9 @@ import java.util.List; import java.util.Set; import java.util.stream.Collectors; + +import fr.istic.service.customdto.EntityId; + import java.util.Optional; /** @@ -109,6 +112,9 @@ public ExamSheet getCSheet(){ @JsonbTransient public Set gradedcomments = new HashSet<>(); + + + // jhipster-needle-entity-add-field - JHipster will add fields here, do not remove @Override @@ -264,6 +270,11 @@ public static PanacheQuery getBestAnswerforQuestionNoAndExamId( long return find("select distinct sr.sheet from StudentResponse sr where sr.question.numero = ?2 and sr.question.exam.id = ?1 and sr.star = true and sr.sheet.pagemin <> -1 and sr.sheet.pagemax <> -1",examId,questionNo ); } + public static PanacheQuery getAllforQuestionNoAndExamId( long examId, int questionNo) { + return find("select distinct sr.sheet.id from StudentResponse sr where sr.question.numero = ?2 and sr.question.exam.id = ?1 and sr.sheet.pagemin <> -1 and sr.sheet.pagemax <> -1",examId,questionNo ).project(EntityId.class); + } + + public static PanacheQuery findAllByQuestionId( long questionId) { return find("select distinct sr from StudentResponse sr where sr.question.id = ?1 and sr.sheet.pagemin <> -1 and sr.sheet.pagemax <> -1",questionId ); @@ -273,7 +284,9 @@ public static PanacheQuery findAllByQuestionIdfetchAnswerfetchH return find("select distinct sr from StudentResponse sr join fetch sr.hybridcommentsValues ah join fetch ah.hybridcomments h2 where sr.question.id = ?1 and sr.sheet.pagemin <> -1 and sr.sheet.pagemax <> -1",questionId ); } - + public static PanacheQuery findAllByPredictionsIds(Long predictionId) { + return find("select sr from StudentResponse sr where sr.prediction.id = ?1", predictionId); + } public static PanacheQuery findAllByGradedCommentsIds( long gradedCommentid) { @@ -321,6 +334,9 @@ public static PanacheQuery getAllStudentResponseWithSameGrade4e public static PanacheQuery getAllStudentResponseWithExamIdNumeroAndSheetId(long examId, int numero, long sheetid) { return find("select distinct sr from StudentResponse sr join fetch sr.sheet as sheet join fetch sr.question as q join fetch q.zone left join fetch sheet.students left join fetch sr.textcomments tc left join fetch sr.gradedcomments gc where sr.question.exam.id = ?1 and sr.question.numero = ?2 and sheet.id = ?3 and sheet.pagemin <> -1 and sheet.pagemax <> -1",examId,numero,sheetid); } + public static PanacheQuery getAllStudentResponseWithExamIdNumeroAndSheetsId(long examId, int numero, List sheetsid) { + return find("select distinct sr from StudentResponse sr join fetch sr.sheet as sheet join fetch sr.question as q join fetch q.zone left join fetch sheet.students left join fetch sr.textcomments tc left join fetch sr.gradedcomments gc where sr.question.exam.id = ?1 and sr.question.numero = ?2 and sheet.id in ?3 and sheet.pagemin <> -1 and sheet.pagemax <> -1",examId,numero,sheetsid); + } public static PanacheQuery getAllStudentResponseWithexamId(long examId) { diff --git a/src/main/java/fr/istic/domain/Template.java b/src/main/java/fr/istic/domain/Template.java index 5f4ace81..6f0d02af 100644 --- a/src/main/java/fr/istic/domain/Template.java +++ b/src/main/java/fr/istic/domain/Template.java @@ -38,7 +38,11 @@ public class Template extends PanacheEntityBase implements Serializable { public String contentContentType; @Column(name = "mark") - public Boolean mark; + public Boolean mark=true; + + @Column(name = "casename") + public Boolean caseboxname=true; + @Column(name = "auto_map_student_copy_to_list") public Boolean autoMapStudentCopyToList; @@ -73,6 +77,7 @@ public String toString() { ", content='" + content + "'" + ", contentContentType='" + contentContentType + "'" + ", mark='" + mark + "'" + + ", caseBoxName='" + caseboxname + "'" + ", autoMapStudentCopyToList='" + autoMapStudentCopyToList + "'" + "}"; } @@ -94,6 +99,7 @@ public static Template update(Template template) { entity.name = template.name; entity.content = template.content; entity.mark = template.mark; + entity.caseboxname = template.caseboxname; entity.autoMapStudentCopyToList = template.autoMapStudentCopyToList; entity.exam = template.exam; } diff --git a/src/main/java/fr/istic/service/ExamSheetService.java b/src/main/java/fr/istic/service/ExamSheetService.java index e53526ea..b3d7b950 100644 --- a/src/main/java/fr/istic/service/ExamSheetService.java +++ b/src/main/java/fr/istic/service/ExamSheetService.java @@ -1,10 +1,20 @@ package fr.istic.service; import io.quarkus.panache.common.Page; +import fr.istic.domain.Answer2HybridGradedComment; import fr.istic.domain.ExamSheet; +import fr.istic.domain.GradedComment; +import fr.istic.domain.HybridGradedComment; +import fr.istic.domain.Question; import fr.istic.domain.Student; +import fr.istic.domain.StudentResponse; +import fr.istic.domain.TextComment; +import fr.istic.domain.User; import fr.istic.service.dto.ExamSheetDTO; +import fr.istic.service.dto.StudentResponseDTO; import fr.istic.service.mapper.ExamSheetMapper; +import fr.istic.service.mapper.StudentResponseMapper; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -12,6 +22,9 @@ import jakarta.inject.Inject; import jakarta.transaction.Transactional; +import java.time.Instant; +import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Optional; import java.util.UUID; @@ -26,6 +39,9 @@ public class ExamSheetService { @Inject ExamSheetMapper examSheetMapper; + @Inject + StudentResponseMapper studentResponseMapper; + @Transactional public ExamSheetDTO persistOrUpdate(ExamSheetDTO examSheetDTO) { log.debug("Request to save ExamSheet : {}", examSheetDTO); @@ -56,78 +72,88 @@ public void delete(Long id) { public Optional findOne(Long id) { log.debug("Request to get ExamSheet : {}", id); return ExamSheet.findByIdOptional(id) - .map(examSheet -> examSheetMapper.toDto((ExamSheet) examSheet)); + .map(examSheet -> examSheetMapper.toDto((ExamSheet) examSheet)); } /** * Get all the examSheets. + * * @param page the pagination information. * @return the list of entities. */ public Paged findAll(Page page) { log.debug("Request to get all ExamSheets"); return new Paged<>(ExamSheet.findAll().page(page)) - .map(examSheet -> examSheetMapper.toDto((ExamSheet) examSheet)); + .map(examSheet -> examSheetMapper.toDto((ExamSheet) examSheet)); } - /** + /** * Get all the examSheets. + * * @param page the pagination information. * @return the list of entities by name. */ public Paged findExamSheetByName(Page page, String name) { log.debug("Request to get all ExamSheets by name"); return new Paged<>(ExamSheet.findExamSheetByName(name).page(page)) - .map(examSheet -> examSheetMapper.toDto((ExamSheet) examSheet)); + .map(examSheet -> examSheetMapper.toDto((ExamSheet) examSheet)); } - public Paged findOrCreateExamSheetByPageMinAndPageMax(Page page, Long scanId, Integer pagemin, + public Paged findOrCreateExamSheetByPageMinAndPageMax(Page page, Long scanId, Integer pagemin, Integer pagemax) throws Exception { - long p = ExamSheet.findExamSheetByScanAndPageminAndPagemax(scanId,pagemin,pagemax).count(); - if (p==0){ - ExamSheetDTO dto = new ExamSheetDTO(); - dto.scanId = scanId; - dto.pagemin = pagemin; - dto.pagemax = pagemax; - dto.name = UUID.randomUUID().toString(); - this.persistOrUpdate(dto); - } - return new Paged<>(ExamSheet.findExamSheetByScanAndPageminAndPagemax(scanId,pagemin,pagemax).page(page)) + long p = ExamSheet.findExamSheetByScanAndPageminAndPagemax(scanId, pagemin, pagemax).count(); + if (p == 0) { + ExamSheetDTO dto = new ExamSheetDTO(); + dto.scanId = scanId; + dto.pagemin = pagemin; + dto.pagemax = pagemax; + dto.name = UUID.randomUUID().toString(); + this.persistOrUpdate(dto); + } + return new Paged<>(ExamSheet.findExamSheetByScanAndPageminAndPagemax(scanId, pagemin, pagemax).page(page)) .map(examSheet -> examSheetMapper.toDto((ExamSheet) examSheet)); - } - + } + public Paged findExamSheetByExamId(Page page, Long examId) throws Exception { + return new Paged<>(ExamSheet.getAll4ExamId(examId).page(page)) + .map(examSheet -> examSheetMapper.toDto((ExamSheet) examSheet)); + } public Paged findOrCreateExamSheetByName(Page page, Long scanId, Integer pageInTemplate, Integer pageInScan) throws Exception { + long nbrpage = ExamSheet.findExamSheetByScanWithoutMinusOne(scanId).count(); - long nbrpage = ExamSheet.findExamSheetByScanWithoutMinusOne(scanId).count(); - - if (nbrpage == pageInScan/pageInTemplate){ - return new Paged<>(ExamSheet.findExamSheetByScanWithoutMinusOne(scanId).page(page)) - .map(examSheet -> examSheetMapper.toDto((ExamSheet) examSheet)); - } else { - for (int i = 0; i< pageInScan/pageInTemplate ;i++){ - long p = ExamSheet.findExamSheetByScanAndPageminAndPagemax(scanId,i*pageInTemplate,i*pageInTemplate + (pageInTemplate-1)).count(); - if (p==0){ - ExamSheetDTO dto = new ExamSheetDTO(); - dto.scanId = scanId; - dto.pagemin = i*pageInTemplate; - dto.pagemax = i*pageInTemplate + (pageInTemplate-1); - dto.name = UUID.randomUUID().toString(); - this.persistOrUpdate(dto); - } + if (nbrpage == pageInScan / pageInTemplate) { + return new Paged<>(ExamSheet.findExamSheetByScanWithoutMinusOne(scanId).page(page)) + .map(examSheet -> examSheetMapper.toDto((ExamSheet) examSheet)); + } else { + for (int i = 0; i < pageInScan / pageInTemplate; i++) { + long p = ExamSheet.findExamSheetByScanAndPageminAndPagemax(scanId, i * pageInTemplate, + i * pageInTemplate + (pageInTemplate - 1)).count(); + if (p == 0) { + ExamSheetDTO dto = new ExamSheetDTO(); + dto.scanId = scanId; + dto.pagemin = i * pageInTemplate; + dto.pagemax = i * pageInTemplate + (pageInTemplate - 1); + dto.name = UUID.randomUUID().toString(); + this.persistOrUpdate(dto); } - for (ExamSheet e: ExamSheet.findExamSheetByScanWithoutMinusOne(scanId).list()){ - if (e.pagemax>=pageInScan){ + } + for (ExamSheet e : ExamSheet.findExamSheetByScanWithoutMinusOne(scanId).list()) { + if (e.pagemax >= pageInScan) { + if (StudentResponse.findStudentResponsesbysheetId(e.id).count() == 0) { e.delete(); + } else { + e.pagemin = -1; + e.pagemax = -1; } } - nbrpage = ExamSheet.findExamSheetByScanWithoutMinusOne(scanId).count(); - if (nbrpage == pageInScan/pageInTemplate){ - return new Paged<>(ExamSheet.findExamSheetByScan(scanId).page(page)) - .map(examSheet -> examSheetMapper.toDto((ExamSheet) examSheet)); + } + nbrpage = ExamSheet.findExamSheetByScanWithoutMinusOne(scanId).count(); + if (nbrpage == pageInScan / pageInTemplate) { + return new Paged<>(ExamSheet.findExamSheetByScan(scanId).page(page)) + .map(examSheet -> examSheetMapper.toDto((ExamSheet) examSheet)); } else { throw (new Exception("Even in trying to create ExamSheets, I got a strange behavior")); } @@ -137,33 +163,232 @@ public Paged findOrCreateExamSheetByName(Page page, Long scanId, I public ExamSheetDTO updateStudent(Long id, List studentsId) throws Exception { ExamSheet exO = ExamSheet.findById(id); - if (exO == null){ + if (exO == null) { throw new Exception("no update student"); } else { List sts = Student.findStudentsbySheetId(id).list(); List sts1 = sts.stream().filter(st -> !studentsId.contains(st.id)).collect(Collectors.toList()); - for (Student s : sts1){ + for (Student s : sts1) { s.examSheets.remove(exO); Student.persistOrUpdate(s); } List stsToUpdate = Student.findStudentsbyIds(studentsId).list(); - - for (Student s : stsToUpdate){ - List sheetsToRemove = s.examSheets.stream().filter(st -> st.scan.id ==exO.scan.id && st.id!= exO.id).collect(Collectors.toList()); - sheetsToRemove.forEach(st-> { + for (Student s : stsToUpdate) { + List sheetsToRemove = s.examSheets.stream() + .filter(st -> st.scan.id == exO.scan.id && st.id != exO.id).collect(Collectors.toList()); + sheetsToRemove.forEach(st -> { s.examSheets.remove(st); Student.persistOrUpdate(s); }); - if (s.examSheets.stream().allMatch(ex -> ex.id != id)){ + if (s.examSheets.stream().allMatch(ex -> ex.id != id)) { s.examSheets.add(exO); exO.students.add(s); Student.persistOrUpdate(s); } } - return this.examSheetMapper.toDto(exO); + return this.examSheetMapper.toDto(exO); + } + + } + + @Transactional + public List toggleTcomments(Long commentid, Long examId, int numero, boolean checked, + List sheetsId, User updatedBy) { + + List response = StudentResponse + .getAllStudentResponseWithExamIdNumeroAndSheetsId(examId, numero, sheetsId).list(); + TextComment comment = TextComment.findById(commentid); + if (comment == null) { + throw new UnsupportedOperationException("No comment found"); + } else { + for (StudentResponse sr : response) { + if (checked) { + sr.textcomments.add(comment); + comment.studentResponses.add(sr); + } else { + sr.textcomments.remove(comment); + comment.studentResponses.remove(sr); + } + sr.lastModifiedDate = Instant.now(); + sr.correctedBy = updatedBy; + + sr = StudentResponse.persistOrUpdate(sr); + comment = TextComment.persistOrUpdate(comment); + } + } + if (checked) { + + List sheeitidswithsr = response.stream().map(sr -> sr.sheet.id).collect(Collectors.toList()); + List sheeitidswithoutsr = sheetsId.stream().filter(s -> !sheeitidswithsr.contains(s)) + .collect(Collectors.toList()); + for (long s : sheeitidswithoutsr) { + StudentResponse sr = new StudentResponse(); + sr.question = Question.findQuestionbyExamIdandnumero(examId, numero).firstResult(); + sr.sheet = ExamSheet.findById(s); + sr.worststar = false; + sr.star = false; + sr.lastModifiedDate = Instant.now(); + sr.correctedBy = updatedBy; + response.add(sr); + sr.textcomments.add(comment); + comment.studentResponses.add(sr); + sr = StudentResponse.persistOrUpdate(sr); + + comment = TextComment.persistOrUpdate(comment); + } + ; + } + + List resultdto = studentResponseMapper.toDto(response); + return resultdto; + } + + + @Transactional + public List toggleGcomments(Long commentid, long examId, int numero, boolean checked, + List sheetsId, User updatedBy) { + + List response = StudentResponse + .getAllStudentResponseWithExamIdNumeroAndSheetsId(examId, numero, sheetsId).list(); + GradedComment comment = GradedComment.findById(commentid); + if (comment == null) { + throw new UnsupportedOperationException("No comment found"); + } else { + for (StudentResponse sr : response) { + if (checked) { + sr.gradedcomments.add(comment); + comment.studentResponses.add(sr); + + } else { + sr.gradedcomments.remove(comment); + comment.studentResponses.remove(sr); + } + sr.lastModifiedDate = Instant.now(); + sr.correctedBy = updatedBy; + sr = StudentResponse.persistOrUpdate(sr); + comment = GradedComment.persistOrUpdate(comment); + } } + if (checked) { + + List sheeitidswithsr = response.stream().map(sr -> sr.sheet.id).collect(Collectors.toList()); + List sheeitidswithoutsr = sheetsId.stream().filter(s -> !sheeitidswithsr.contains(s)) + .collect(Collectors.toList()); + for (long s : sheeitidswithoutsr) { + StudentResponse sr = new StudentResponse(); + sr.question = Question.findQuestionbyExamIdandnumero(examId, numero).firstResult(); + + sr.sheet = ExamSheet.findById(s); + sr.worststar = false; + sr.star = false; + sr.lastModifiedDate = Instant.now(); + sr.correctedBy = updatedBy; + sr.gradedcomments.add(comment); + comment.studentResponses.add(sr); + sr = StudentResponse.persistOrUpdate(sr); + comment = GradedComment.persistOrUpdate(comment); + response.add(sr); + } + ; + } + + List resultdto = studentResponseMapper.toDto(response); + return resultdto; + } + + @Transactional + public List toggleHcomments(Long commentid, long examId, int numero, int step, + List sheetsId, User updatedBy) { + + List response = StudentResponse + .getAllStudentResponseWithExamIdNumeroAndSheetsId(examId, numero, sheetsId).list(); + HybridGradedComment comment = HybridGradedComment.findById(commentid); + if (comment == null || step > comment.step || step < 0) { + throw new UnsupportedOperationException("No comment found or invalid step"); + } else { + for (StudentResponse sr : response) { + + sr.lastModifiedDate = Instant.now(); + sr.correctedBy = updatedBy; + sr = StudentResponse.persistOrUpdate(sr); + List acs =Answer2HybridGradedComment.findAllWithResponseIdAndHybridCommentId(sr.id, commentid).list(); + if (acs.size()>0){ + acs.get(0).stepValue = step; + Answer2HybridGradedComment.persistOrUpdate(acs.get(0)); + }else { + Answer2HybridGradedComment ac = new Answer2HybridGradedComment(); + ac.stepValue = step; + ac.hybridcomments = comment; + ac.studentResponse = sr; + sr.hybridcommentsValues.add(ac); + comment.valueAnswers.add(ac); + ac= Answer2HybridGradedComment.persistOrUpdate(ac); + sr = StudentResponse.persistOrUpdate(sr); + comment = HybridGradedComment.persistOrUpdate(comment); + } + } + } + + List sheeitidswithsr = response.stream().map(sr -> sr.sheet.id).collect(Collectors.toList()); + List sheeitidswithoutsr = sheetsId.stream().filter(s -> !sheeitidswithsr.contains(s)) + .collect(Collectors.toList()); + for (long s : sheeitidswithoutsr) { + StudentResponse sr = new StudentResponse(); + sr.question = Question.findQuestionbyExamIdandnumero(examId, numero).firstResult(); + sr.sheet = ExamSheet.findById(s); + sr.worststar = false; + sr.star = false; + sr.lastModifiedDate = Instant.now(); + sr.correctedBy = updatedBy; + + Answer2HybridGradedComment ac = new Answer2HybridGradedComment(); + ac.stepValue = step; + ac.hybridcomments = comment; + ac.studentResponse = sr; + sr.hybridcommentsValues.add(ac); + comment.valueAnswers.add(ac); + ac = Answer2HybridGradedComment.persistOrUpdate(ac); + sr = StudentResponse.persistOrUpdate(sr); + comment = HybridGradedComment.persistOrUpdate(comment); + response.add(sr); + } + + List resultdto = studentResponseMapper.toDto(response); + return resultdto; + } + + public List updateNotes(Long examId, int numero, int step, List sheetsId, User updatedBy) { + List response = StudentResponse + .getAllStudentResponseWithExamIdNumeroAndSheetsId(examId, numero, sheetsId).list(); + for (StudentResponse sr : response) { + sr.lastModifiedDate = Instant.now(); + sr.correctedBy = updatedBy; + sr.quarternote = 4*step; + sr = StudentResponse.persistOrUpdate(sr); + } + + List sheeitidswithsr = response.stream().map(sr -> sr.sheet.id).collect(Collectors.toList()); + List sheeitidswithoutsr = sheetsId.stream().filter(s -> !sheeitidswithsr.contains(s)) + .collect(Collectors.toList()); + for (long s : sheeitidswithoutsr) { + StudentResponse sr = new StudentResponse(); + sr.question = Question.findQuestionbyExamIdandnumero(examId, numero).firstResult(); + + sr.sheet = ExamSheet.findById(s); + sr.worststar = false; + sr.star = false; + sr.quarternote = 4*step; + sr.lastModifiedDate = Instant.now(); + sr.correctedBy = updatedBy; + sr = StudentResponse.persistOrUpdate(sr); + response.add(sr); + } + ; + + List resultdto = studentResponseMapper.toDto(response); + return resultdto; } diff --git a/src/main/java/fr/istic/service/PredictionService.java b/src/main/java/fr/istic/service/PredictionService.java new file mode 100644 index 00000000..24aabde5 --- /dev/null +++ b/src/main/java/fr/istic/service/PredictionService.java @@ -0,0 +1,115 @@ +package fr.istic.service; + +import io.quarkus.panache.common.Page; +import fr.istic.domain.StudentResponse; +import fr.istic.domain.Prediction; +import fr.istic.service.customdto.EntityId; +import fr.istic.service.customdto.PredictionsIdsDto; +import fr.istic.service.dto.PredictionDTO; +import fr.istic.service.mapper.PredictionMapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import jakarta.transaction.Transactional; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +@ApplicationScoped +@Transactional +public class PredictionService { + + private final Logger log = LoggerFactory.getLogger(PredictionService.class); + + @Inject + PredictionMapper predictionMapper; + + /** + * Persist or update a prediction entity. + * + * @param predictionDTO the DTO of the entity. + * @return the persisted or updated DTO. + */ + @Transactional + public PredictionDTO persistOrUpdate(PredictionDTO predictionDTO) { + log.debug("Request to save Prediction : {}", predictionDTO); + var prediction = predictionMapper.toEntity(predictionDTO); + prediction = Prediction.persistOrUpdate(prediction); + return predictionMapper.toDto(prediction); + } + + /** + * Delete the Prediction by ID. + * + * @param id the ID of the entity. + */ + @Transactional + public void delete(Long id) { + log.debug("Request to delete Prediction : {}", id); + Prediction.findByIdOptional(id).ifPresent(prediction -> { + // Delete the prediction entity + prediction.delete(); + }); + } + + + /** + * Delete the Prediction by ID. + * + * @param id the ID of the entity. + */ + @Transactional + public void deleteByQuestionId(Long questionId) { + log.debug("Request to delete Prediction for question {}", questionId); + Prediction.deleteByQId(questionId); + } + + + + /** + * Get one Prediction by ID. + * + * @param id the ID of the entity. + * @return the entity as an optional DTO. + */ + public Optional findOne(Long id) { + log.debug("Request to get Prediction : {}", id); + return Prediction.findByIdOptional(id) + .map(prediction -> predictionMapper.toDto((Prediction) prediction)); + } + + /** + * Get all the Predictions. + * + * @param page the pagination information. + * @return a paged list of entities. + */ + public Paged findAll(Page page) { + log.debug("Request to get all Predictions"); + return new Paged<>(Prediction.findAll().page(page)) + .map(prediction -> predictionMapper.toDto((Prediction) prediction)); + } + + /** + * Get all the Predictions by Question ID. + * + * @param page the pagination information. + * @param questionId the ID of the related question. + * @return a paged list of entities. + */ + public Paged findPredictionByQuestionId(Page page, long questionId) { + log.debug("Request to get all Predictions by Question ID"); + return new Paged<>(Prediction.findByQuestionId(questionId).page(page)) + .map(prediction -> predictionMapper.toDto((Prediction) prediction)); + } + + public List findPredictionWithoutStudentResponse(PredictionsIdsDto predictionIdsDTO){ + List ids = StudentResponse.getAllforQuestionNoAndExamId(predictionIdsDTO.getExamId(), predictionIdsDTO.getNumero()).list(); + List idsList = ids.stream().map(EntityId::getId).collect(Collectors.toList()); + return predictionIdsDTO.getPredictionsids().stream().filter(id -> !idsList.contains(id)).collect(Collectors.toList()); + + } +} diff --git a/src/main/java/fr/istic/service/SecurityService.java b/src/main/java/fr/istic/service/SecurityService.java index 2d26dd09..1280f091 100644 --- a/src/main/java/fr/istic/service/SecurityService.java +++ b/src/main/java/fr/istic/service/SecurityService.java @@ -17,6 +17,7 @@ import fr.istic.domain.FinalResult; import fr.istic.domain.GradedComment; import fr.istic.domain.HybridGradedComment; +import fr.istic.domain.Prediction; import fr.istic.domain.Question; import fr.istic.domain.Scan; import fr.istic.domain.Student; @@ -83,6 +84,8 @@ public boolean canAccess(SecurityContext ctx,long id, Class entity ){ number = HybridGradedComment.canAccess(id, userLogin.get()).count(); }else if (entity.equals(Answer2HybridGradedComment.class)){ number = Answer2HybridGradedComment.canAccess(id, userLogin.get()).count(); + }else if (entity.equals(Prediction.class)){ + number = Prediction.canAccess(id, userLogin.get()).count(); } else if (entity.equals(Zone.class)){ number = Zone.canAccess1(id, userLogin.get()).count(); diff --git a/src/main/java/fr/istic/service/StudentResponseService.java b/src/main/java/fr/istic/service/StudentResponseService.java index cb8e677a..5ff399a3 100644 --- a/src/main/java/fr/istic/service/StudentResponseService.java +++ b/src/main/java/fr/istic/service/StudentResponseService.java @@ -128,6 +128,19 @@ public Paged findStudentResponsesbysheetIdAndquestionId(Page .map(studentResponse -> studentResponseMapper.toDto((StudentResponse) studentResponse)); } + /** + * Get all the studentResponses. + * @param page the pagination information. + * @return the list of entities. + */ + public Paged findStudentResponsesbyQuestionId + (Page page, Long questionId) { + log.debug("Request to get all StudentResponses"); + return new Paged<>(StudentResponse.findAllByQuestionId(questionId).page(page)) + .map(studentResponse -> studentResponseMapper.toDto((StudentResponse) studentResponse)); + } + + @Transactional public Optional partialeNoteUpdate(StudentResponseNote notedto, Long id) { log.debug("Request to patch partialeNoteUpdate " + id); diff --git a/src/main/java/fr/istic/service/TemplateService.java b/src/main/java/fr/istic/service/TemplateService.java index aef24388..093a6ca6 100644 --- a/src/main/java/fr/istic/service/TemplateService.java +++ b/src/main/java/fr/istic/service/TemplateService.java @@ -8,6 +8,7 @@ import io.minio.errors.XmlParserException; import io.quarkus.panache.common.Page; import fr.istic.domain.Template; +import fr.istic.service.customdto.TemplateCaseDTO; import fr.istic.service.dto.TemplateDTO; import fr.istic.service.dto.TemplateDTOContent; import fr.istic.service.mapper.TemplateContentMapper; @@ -154,5 +155,17 @@ public Paged findAll(Page page) { return new Paged<>(Template.findAll().page(page)) .map(template -> templateMapper.toDto((Template) template)); } + @Transactional + public Optional partialUpdate(TemplateCaseDTO tDTO, Long id) { + Template t = Template.findById(id); + if (t != null){ + t.caseboxname = tDTO.caseboxname; + t = Template.persistOrUpdate(t); + TemplateDTO dto = templateMapper.toDto(t); + return Optional.of(dto); + } + return Optional.empty(); + + } } diff --git a/src/main/java/fr/istic/service/customdto/EntityId.java b/src/main/java/fr/istic/service/customdto/EntityId.java new file mode 100644 index 00000000..86774f38 --- /dev/null +++ b/src/main/java/fr/istic/service/customdto/EntityId.java @@ -0,0 +1,21 @@ +package fr.istic.service.customdto; + +import io.quarkus.runtime.annotations.RegisterForReflection; + +@RegisterForReflection +public class EntityId { + + public EntityId(long id){ + this.id = id; + } + + long id; + + public long getId() { + return this.id; + } + + public void setId(long id) { + this.id = id; + } +} diff --git a/src/main/java/fr/istic/service/customdto/PredictionsIdsDto.java b/src/main/java/fr/istic/service/customdto/PredictionsIdsDto.java new file mode 100644 index 00000000..fb2fb7e8 --- /dev/null +++ b/src/main/java/fr/istic/service/customdto/PredictionsIdsDto.java @@ -0,0 +1,29 @@ +package fr.istic.service.customdto; +import java.util.List; + +import io.quarkus.runtime.annotations.RegisterForReflection; +@RegisterForReflection +public class PredictionsIdsDto { + private List predictionsids; + private long examId; + private int numero; + + public long getExamId() { + return this.examId; + } + + public void setExamId(long examId) { + this.examId = examId; + } + + public int getNumero() { + return this.numero; + } + + public void setNumero(int numero) { + this.numero = numero; + } + + public List getPredictionsids() { return predictionsids; } + public void setPredictionsids(List value) { this.predictionsids = value; } +} diff --git a/src/main/java/fr/istic/service/customdto/TemplateCaseDTO.java b/src/main/java/fr/istic/service/customdto/TemplateCaseDTO.java new file mode 100644 index 00000000..697bd710 --- /dev/null +++ b/src/main/java/fr/istic/service/customdto/TemplateCaseDTO.java @@ -0,0 +1,50 @@ +package fr.istic.service.customdto; + + +import io.quarkus.runtime.annotations.RegisterForReflection; +import jakarta.validation.constraints.*; +import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * A DTO for the {@link fr.istic.domain.Template} entity. + */ +@RegisterForReflection +public class TemplateCaseDTO implements Serializable { + + public Long id; + + + public String contentContentType; + + @JsonProperty("caseboxname") + public Boolean caseboxname; + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof TemplateCaseDTO)) { + return false; + } + + return id != null && id.equals(((TemplateCaseDTO) o).id); + } + + @Override + public int hashCode() { + return 31; + } + + @Override + public String toString() { + return "TemplateCaseDTO{" + + "id=" + id + + ", caseboxname='" + caseboxname + "'" + + "}"; + } +} diff --git a/src/main/java/fr/istic/service/dto/CourseDTO.java b/src/main/java/fr/istic/service/dto/CourseDTO.java index f95a7624..0266b05b 100644 --- a/src/main/java/fr/istic/service/dto/CourseDTO.java +++ b/src/main/java/fr/istic/service/dto/CourseDTO.java @@ -19,6 +19,9 @@ public class CourseDTO implements Serializable { @NotNull public String name; + public Boolean archived = false; + + public Set profs = new HashSet<>(); @Override @@ -43,6 +46,7 @@ public String toString() { return "CourseDTO{" + "id=" + id + ", name='" + name + "'" + + ", archived='" + archived + "'" + ", profs='" + profs + "'" + "}"; } diff --git a/src/main/java/fr/istic/service/dto/ExamDTO.java b/src/main/java/fr/istic/service/dto/ExamDTO.java index e2f59b08..281d20b4 100644 --- a/src/main/java/fr/istic/service/dto/ExamDTO.java +++ b/src/main/java/fr/istic/service/dto/ExamDTO.java @@ -19,6 +19,8 @@ public class ExamDTO implements Serializable { public Long templateId; public String templateName; + public Boolean templateMark; + public Boolean templateNameBoxCase; public Long idzoneId; public Long namezoneId; public Long firstnamezoneId; @@ -52,6 +54,8 @@ public String toString() { ", name='" + name + "'" + ", templateId=" + templateId + ", templateName='" + templateName + "'" + + ", templateMark='" + templateMark + "'" + + ", templateNameBoxCase='" + templateNameBoxCase + "'" + ", idzoneId=" + idzoneId + ", namezoneId=" + namezoneId + ", firstnamezoneId=" + firstnamezoneId + diff --git a/src/main/java/fr/istic/service/dto/PredictionDTO.java b/src/main/java/fr/istic/service/dto/PredictionDTO.java new file mode 100644 index 00000000..86663aaf --- /dev/null +++ b/src/main/java/fr/istic/service/dto/PredictionDTO.java @@ -0,0 +1,60 @@ +package fr.istic.service.dto; + +import io.quarkus.runtime.annotations.RegisterForReflection; +import java.io.Serializable; +import jakarta.persistence.Lob; + +/** + * A DTO for the {@link fr.istic.domain.Prediction} entity. + */ +@RegisterForReflection +public class PredictionDTO implements Serializable { + + public Long id; + + public String text; + + @Lob + public String jsonData; + + public String questionNumber; + + public Long questionId; + + public Long sheetId; + public Long sheetPageMin; + public Long sheetPageMax; + + public Double predictionconfidence; + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof PredictionDTO)) { + return false; + } + + return id != null && id.equals(((PredictionDTO) o).id); + } + + @Override + public int hashCode() { + return 31; + } + + @Override + public String toString() { + return "PredictionDTO{" + + "id=" + id + + ", text='" + text + "'" + + ", jsonData='" + jsonData + "'" + + ", predictionconfidence='" + predictionconfidence + "'" + + ", questionNumber='" + questionNumber + "'" + + ", questionId=" + questionId + + ", sheetId=" + sheetId + + "}"; + } +} diff --git a/src/main/java/fr/istic/service/dto/StudentResponseDTO.java b/src/main/java/fr/istic/service/dto/StudentResponseDTO.java index e9e47747..3828a01c 100644 --- a/src/main/java/fr/istic/service/dto/StudentResponseDTO.java +++ b/src/main/java/fr/istic/service/dto/StudentResponseDTO.java @@ -25,6 +25,8 @@ public class StudentResponseDTO implements Serializable { public String questionNumero; public Long sheetId; public String sheetName; + public Integer sheetPageMin; + public Integer sheetPageMax; public String correctedByInfo; public String correctedByMail; public Instant lastModifiedDate; @@ -60,6 +62,8 @@ public String toString() { ", questionNumero='" + questionNumero + "'" + ", sheetId=" + sheetId + ", sheetName='" + sheetName + "'" + + ", sheetPageMin='" + sheetPageMin + "'" + + ", sheetPageMax='" + sheetPageMax + "'" + ", textcomments='" + textcomments + "'" + ", gradedcomments='" + gradedcomments + "'" + "}"; diff --git a/src/main/java/fr/istic/service/dto/TemplateDTO.java b/src/main/java/fr/istic/service/dto/TemplateDTO.java index aaa02211..4f6f3092 100644 --- a/src/main/java/fr/istic/service/dto/TemplateDTO.java +++ b/src/main/java/fr/istic/service/dto/TemplateDTO.java @@ -5,6 +5,8 @@ import jakarta.validation.constraints.*; import java.io.Serializable; +import com.fasterxml.jackson.annotation.JsonProperty; + /** * A DTO for the {@link fr.istic.domain.Template} entity. */ @@ -18,8 +20,13 @@ public class TemplateDTO implements Serializable { public String contentContentType; + @JsonProperty("mark") public Boolean mark; + @JsonProperty("caseboxname") + public Boolean caseboxname; + + public Boolean autoMapStudentCopyToList; @@ -46,6 +53,7 @@ public String toString() { "id=" + id + ", name='" + name + "'" + ", mark='" + mark + "'" + + ", caseboxname='" + caseboxname + "'" + ", autoMapStudentCopyToList='" + autoMapStudentCopyToList + "'" + "}"; } diff --git a/src/main/java/fr/istic/service/dto/TemplateDTOContent.java b/src/main/java/fr/istic/service/dto/TemplateDTOContent.java index 8b03d6e3..f981984d 100644 --- a/src/main/java/fr/istic/service/dto/TemplateDTOContent.java +++ b/src/main/java/fr/istic/service/dto/TemplateDTOContent.java @@ -5,6 +5,9 @@ import jakarta.validation.constraints.*; import java.io.Serializable; import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonProperty; + import jakarta.persistence.Lob; /** @@ -27,6 +30,8 @@ public class TemplateDTOContent implements Serializable { public Boolean autoMapStudentCopyToList; + @JsonProperty("caseboxname") + public Boolean caseboxname; @Override public boolean equals(Object o) { @@ -50,6 +55,7 @@ public String toString() { return "TemplateDTO{" + "id=" + id + ", name='" + name + "'" + + ", caseboxname='" + caseboxname + "'" + ", content='" + content + "'" + ", mark='" + mark + "'" + ", autoMapStudentCopyToList='" + autoMapStudentCopyToList + "'" + diff --git a/src/main/java/fr/istic/service/mapper/ExamMapper.java b/src/main/java/fr/istic/service/mapper/ExamMapper.java index 5bdaba25..e5e722c1 100644 --- a/src/main/java/fr/istic/service/mapper/ExamMapper.java +++ b/src/main/java/fr/istic/service/mapper/ExamMapper.java @@ -14,6 +14,8 @@ public interface ExamMapper extends EntityMapper { @Mapping(source = "template.id", target = "templateId") @Mapping(source = "template.name", target = "templateName") + @Mapping(source = "template.mark", target = "templateMark") + @Mapping(source = "template.caseboxname", target = "templateNameBoxCase") @Mapping(source = "idzone.id", target = "idzoneId") @Mapping(source = "namezone.id", target = "namezoneId") @Mapping(source = "firstnamezone.id", target = "firstnamezoneId") diff --git a/src/main/java/fr/istic/service/mapper/PredictionMapper.java b/src/main/java/fr/istic/service/mapper/PredictionMapper.java new file mode 100644 index 00000000..badd52d0 --- /dev/null +++ b/src/main/java/fr/istic/service/mapper/PredictionMapper.java @@ -0,0 +1,32 @@ +package fr.istic.service.mapper; + +import fr.istic.domain.*; +import fr.istic.service.dto.PredictionDTO; + +import org.mapstruct.*; + +/** + * Mapper for the entity {@link Prediction} and its DTO {@link PredictionDTO}. + */ +@Mapper(componentModel = "jakarta", uses = {QuestionMapper.class, ExamSheetMapper.class}, injectionStrategy = InjectionStrategy.CONSTRUCTOR) +public interface PredictionMapper extends EntityMapper { + + @Mapping(source = "question.id", target = "questionId") + @Mapping(source = "sheet.id", target = "sheetId") + @Mapping(source = "sheet.pagemin", target = "sheetPageMin") + @Mapping(source = "sheet.pagemax", target = "sheetPageMax") + PredictionDTO toDto(Prediction prediction); + + @Mapping(source = "questionId", target = "question") + @Mapping(source = "sheetId", target = "sheet") + Prediction toEntity(PredictionDTO predictionDTO); + + default Prediction fromId(Long id) { + if (id == null) { + return null; + } + Prediction prediction = new Prediction(); + prediction.id = id; + return prediction; + } +} diff --git a/src/main/java/fr/istic/service/mapper/StudentResponseMapper.java b/src/main/java/fr/istic/service/mapper/StudentResponseMapper.java index 59a87829..69131b35 100644 --- a/src/main/java/fr/istic/service/mapper/StudentResponseMapper.java +++ b/src/main/java/fr/istic/service/mapper/StudentResponseMapper.java @@ -16,6 +16,8 @@ public interface StudentResponseMapper extends EntityMapper sheetsId, + @Context SecurityContext ctx) { + + if (ctx.getUserPrincipal().getName() != null) { + + var userLogin = Optional + .ofNullable(ctx.getUserPrincipal().getName()); + if (!userLogin.isPresent()) { + throw new AccountResourceException("Current user login not found"); + } + var user = User.findOneByLogin(userLogin.get()); + if (user.isPresent()) { + + if (commentid == null || commentid <= 0) { + throw new BadRequestAlertException("Invalid commentid id", ENTITY_NAME, "idnull"); + } + + for (Long id : sheetsId) { + if (!securityService.canAccess(ctx, id, ExamSheet.class)) { + return Response.status(403, "Current user cannot access to this ressource").build(); + } + } + + List result = null; + try { + result = examSheetService.toggleTcomments(commentid, examid, numero, checked, sheetsId, user.get()); + } catch (Exception e) { + e.printStackTrace(); + } + if (result != null) { + var response = Response.ok().entity(result); + return response.build(); + } else { + var response = Response.noContent(); + return response.build(); + + } + }else { + return Response.status(403, "Current user cannot access to this ressource").build(); + } + + } else { + return Response.status(403, "Current user cannot access to this ressource").build(); + } + } + + @PUT + @Path("/togglegcomments/{examid}/{commentid}/{numero}/{checked}") + @RolesAllowed({ AuthoritiesConstants.USER, AuthoritiesConstants.ADMIN }) + public Response toggleGcomments(@PathParam("examid") Long examid, @PathParam("commentid") Long commentid, + @PathParam("numero") int numero, @PathParam("checked") boolean checked, List sheetsId, + @Context SecurityContext ctx) { + + if (ctx.getUserPrincipal().getName() != null) { + + var userLogin = Optional + .ofNullable(ctx.getUserPrincipal().getName()); + if (!userLogin.isPresent()) { + throw new AccountResourceException("Current user login not found"); + } + var user = User.findOneByLogin(userLogin.get()); + if (user.isPresent()) { + + if (commentid == null || commentid <= 0) { + throw new BadRequestAlertException("Invalid commentid id", ENTITY_NAME, "idnull"); + } + + for (Long id : sheetsId) { + if (!securityService.canAccess(ctx, id, ExamSheet.class)) { + return Response.status(403, "Current user cannot access to this ressource").build(); + } + } + + List result = null; + try { + result = examSheetService.toggleGcomments(commentid, examid, numero, checked, sheetsId, user.get()); + } catch (Exception e) { + e.printStackTrace(); + } + if (result != null) { + var response = Response.ok().entity(result); + return response.build(); + } else { + var response = Response.noContent(); + return response.build(); + + } + }else { + return Response.status(403, "Current user cannot access to this ressource").build(); + } + + } else { + return Response.status(403, "Current user cannot access to this ressource").build(); + } + } + + @PUT + @Path("/togglehcomments/{examid}/{commentid}/{numero}/{step}") + @RolesAllowed({ AuthoritiesConstants.USER, AuthoritiesConstants.ADMIN }) + public Response toggleHcomments(@PathParam("examid") Long examid, @PathParam("commentid") Long commentid, + @PathParam("numero") int numero, @PathParam("step") int step, List sheetsId, + @Context SecurityContext ctx) { + + if (ctx.getUserPrincipal().getName() != null) { + + var userLogin = Optional + .ofNullable(ctx.getUserPrincipal().getName()); + if (!userLogin.isPresent()) { + throw new AccountResourceException("Current user login not found"); + } + var user = User.findOneByLogin(userLogin.get()); + if (user.isPresent()) { + + if (commentid == null || commentid <= 0) { + throw new BadRequestAlertException("Invalid commentid id", ENTITY_NAME, "idnull"); + } + + for (Long id : sheetsId) { + if (!securityService.canAccess(ctx, id, ExamSheet.class)) { + return Response.status(403, "Current user cannot access to this ressource").build(); + } + } + + List result = null; + try { + result = examSheetService.toggleHcomments(commentid, examid, numero, step, sheetsId, user.get()); + } catch (Exception e) { + e.printStackTrace(); + } + if (result != null) { + var response = Response.ok().entity(result); + return response.build(); + } else { + var response = Response.noContent(); + return response.build(); + + } + }else { + return Response.status(403, "Current user cannot access to this ressource").build(); + } + + } else { + return Response.status(403, "Current user cannot access to this ressource").build(); + } + } + + + @PUT + @Path("/updatenotes/{examid}/{numero}/{step}") + @RolesAllowed({ AuthoritiesConstants.USER, AuthoritiesConstants.ADMIN }) + public Response updateNotes(@PathParam("examid") Long examid, + @PathParam("numero") int numero, @PathParam("step") int step, List sheetsId, + @Context SecurityContext ctx) { + + if (ctx.getUserPrincipal().getName() != null) { + + var userLogin = Optional + .ofNullable(ctx.getUserPrincipal().getName()); + if (!userLogin.isPresent()) { + throw new AccountResourceException("Current user login not found"); + } + var user = User.findOneByLogin(userLogin.get()); + if (user.isPresent()) { + + if (examid == null || examid <= 0) { + throw new BadRequestAlertException("Invalid commentid id", ENTITY_NAME, "idnull"); + } + + for (Long id : sheetsId) { + if (!securityService.canAccess(ctx, id, ExamSheet.class)) { + return Response.status(403, "Current user cannot access to this ressource").build(); + } + } + + List result = null; + try { + result = examSheetService.updateNotes(examid, numero, step, sheetsId, user.get()); + } catch (Exception e) { + e.printStackTrace(); + } + if (result != null) { + var response = Response.ok().entity(result); + return response.build(); + } else { + var response = Response.noContent(); + return response.build(); + + } + }else { + return Response.status(403, "Current user cannot access to this ressource").build(); + } + + } else { + return Response.status(403, "Current user cannot access to this ressource").build(); + } + } + + /** * {@code DELETE /exam-sheets/:id} : delete the "id" examSheet. * @@ -236,6 +440,19 @@ public Response getAllExamSheets(@BeanParam PageRequestVM pageRequest, @BeanPara log.error("query sheets but with inconsistency in pages min and max " + pagemin + " " + pagemax + " " + scanId.get(0)); } + } else if (param.containsKey("examId")) { + List examId = (List) param.get("examId"); + try { + result = examSheetService.findExamSheetByExamId(page, + Long.valueOf("" + examId.get(0))); + } catch (NumberFormatException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } else { diff --git a/src/main/java/fr/istic/web/rest/PredictionResource.java b/src/main/java/fr/istic/web/rest/PredictionResource.java new file mode 100644 index 00000000..ecd3be73 --- /dev/null +++ b/src/main/java/fr/istic/web/rest/PredictionResource.java @@ -0,0 +1,245 @@ +package fr.istic.web.rest; + +import static jakarta.ws.rs.core.UriBuilder.fromPath; + +import fr.istic.service.PredictionService; +import fr.istic.web.rest.errors.AccountResourceException; +import fr.istic.web.rest.errors.BadRequestAlertException; +import fr.istic.web.util.HeaderUtil; +import fr.istic.web.util.ResponseUtil; +import fr.istic.service.dto.PredictionDTO; + +import org.eclipse.microprofile.config.inject.ConfigProperty; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import fr.istic.domain.Authority; +import fr.istic.domain.StudentResponse; +import fr.istic.domain.Prediction; +import fr.istic.domain.Question; +import fr.istic.domain.User; +import fr.istic.security.AuthoritiesConstants; +import fr.istic.service.Paged; +import fr.istic.service.SecurityService; +import fr.istic.service.customdto.PredictionsIdsDto; +import fr.istic.web.rest.vm.PageRequestVM; +import fr.istic.web.rest.vm.SortRequestVM; +import fr.istic.web.util.PaginationUtil; + +import jakarta.annotation.security.RolesAllowed; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import jakarta.ws.rs.*; +import jakarta.ws.rs.core.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +/** + * REST controller for managing {@link fr.istic.domain.Prediction}. + */ +@Path("/api/predictions") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +@ApplicationScoped +public class PredictionResource { + + private final Logger log = LoggerFactory.getLogger(PredictionResource.class); + + private static final String ENTITY_NAME = "prediction"; + + @ConfigProperty(name = "application.name") + String applicationName; + + @Inject + SecurityService securityService; + + @Inject + PredictionService predictionService; + + /** + * {@code POST /predictions} : Create a new prediction. + * + * @param predictionDTO the predictionDTO to create. + * @return the {@link Response} with status {@code 201 (Created)} and with body the new predictionDTO, or with status {@code 400 (Bad Request)} if the prediction already has an ID. + */ + @POST + @RolesAllowed({AuthoritiesConstants.USER, AuthoritiesConstants.ADMIN}) + public Response createPrediction(PredictionDTO predictionDTO, @Context UriInfo uriInfo) { + log.debug("REST request to save Prediction : {}", predictionDTO); + if (predictionDTO.id != null) { + throw new BadRequestAlertException("A new prediction cannot already have an ID", ENTITY_NAME, "idexists"); + } + var result = predictionService.persistOrUpdate(predictionDTO); + var response = Response.created(fromPath(uriInfo.getPath()).path(result.id.toString()).build()).entity(result); + HeaderUtil.createEntityCreationAlert(applicationName, true, ENTITY_NAME, result.id.toString()).forEach(response::header); + return response.build(); + } + + @POST + @Path("/findPredictionWithoutStudentResponse") + @RolesAllowed({AuthoritiesConstants.USER, AuthoritiesConstants.ADMIN}) + public Response findPredictionWithoutStudentResponse(PredictionsIdsDto predictionIdsDTO, @Context UriInfo uriInfo) { + log.debug("REST request to save Prediction : {}", predictionIdsDTO); + if (predictionIdsDTO.getPredictionsids().size()==0) { + throw new BadRequestAlertException("Please provide a list of prediction ids", ENTITY_NAME, "idnull"); + } + List res = predictionService.findPredictionWithoutStudentResponse(predictionIdsDTO); + PredictionsIdsDto dto = new PredictionsIdsDto(); + dto.setPredictionsids(res); + return Response.ok(dto).build(); + } + + /** + * {@code PUT /predictions} : Updates an existing prediction. + * + * @param predictionDTO the predictionDTO to update. + * @return the {@link Response} with status {@code 200 (OK)} and with body the updated predictionDTO, + * or with status {@code 400 (Bad Request)} if the predictionDTO is not valid, + * or with status {@code 500 (Internal Server Error)} if the predictionDTO couldn't be updated. + */ + @PUT + @RolesAllowed({AuthoritiesConstants.USER, AuthoritiesConstants.ADMIN}) + public Response updatePrediction(PredictionDTO predictionDTO, @Context SecurityContext ctx) { + log.debug("REST request to update Prediction : {}", predictionDTO); + if (predictionDTO.id == null) { + throw new BadRequestAlertException("Invalid id", ENTITY_NAME, "idnull"); + } + if (!securityService.canAccess(ctx, predictionDTO.id, Prediction.class)) { + return Response.status(403, "Current user cannot access to this resource").build(); + } + var result = predictionService.persistOrUpdate(predictionDTO); + var response = Response.ok().entity(result); + HeaderUtil.createEntityUpdateAlert(applicationName, true, ENTITY_NAME, predictionDTO.id.toString()).forEach(response::header); + return response.build(); + } + + /** + * {@code DELETE /predictions/:id} : delete the "id" prediction. + * + * @param id the id of the predictionDTO to delete. + * @return the {@link Response} with status {@code 204 (NO_CONTENT)}. + */ + @DELETE + @Path("/{id}") + @RolesAllowed({AuthoritiesConstants.USER, AuthoritiesConstants.ADMIN}) + public Response deletePrediction(@PathParam("id") Long id, @Context SecurityContext ctx) { + log.debug("REST request to delete Prediction : {}", id); + try { + // Security check + if (!securityService.canAccess(ctx, id, Prediction.class)) { + log.error("User is not authorized to delete Prediction with id: {}", id); + return Response.status(403, "Current user cannot access this resource").build(); + } + + // Attempt deletion + predictionService.delete(id); + log.info("Prediction with id {} deleted successfully", id); + } catch (Exception e) { + log.error("Failed to delete Prediction with id {}: {}", id, e.getMessage(), e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity("Failed to delete Prediction with id: " + id + ". Error: " + e.getMessage()) + .build(); + } + + // If successful + var response = Response.noContent(); + HeaderUtil.createEntityDeletionAlert(applicationName, true, ENTITY_NAME, id.toString()).forEach(response::header); + return response.build(); + } + + + /** + * {@code DELETE /predictions/question/:questionId} : delete the "id" prediction. + * + * @param id the questionId of the question associated to prediction to delete. + * @return the {@link Response} with status {@code 204 (NO_CONTENT)}. + */ + @DELETE + @Path("/question/{questionId}") + @RolesAllowed({AuthoritiesConstants.USER, AuthoritiesConstants.ADMIN}) + public Response deletePredictionByQuestionId(@PathParam("questionId") Long id, @Context SecurityContext ctx) { + log.debug("REST request to delete Prediction : {}", id); + try { + // Security check + if (!securityService.canAccess(ctx, id, Question.class)) { + log.error("User is not authorized to delete Prediction with question id: {}", id); + return Response.status(403, "Current user cannot access this resource").build(); + } + + // Attempt deletion + predictionService.deleteByQuestionId(id); + log.info("Prediction with question id {} deleted successfully", id); + } catch (Exception e) { + log.error("Failed to delete Prediction with question id {}: {}", id, e.getMessage(), e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity("Failed to delete Prediction with id: " + id + ". Error: " + e.getMessage()) + .build(); + } + + // If successful + var response = Response.noContent(); + HeaderUtil.createEntityDeletionAlert(applicationName, true, ENTITY_NAME, id.toString()).forEach(response::header); + return response.build(); + } + + + /** + * {@code GET /predictions} : get all the predictions. + * + * @param pageRequest the pagination information. + * @return the {@link Response} with status {@code 200 (OK)} and the list of predictions in body. + */ + @GET + @RolesAllowed({AuthoritiesConstants.USER, AuthoritiesConstants.ADMIN}) + public Response getAllPredictions(@BeanParam PageRequestVM pageRequest, @BeanParam SortRequestVM sortRequest, @Context UriInfo uriInfo, @Context SecurityContext ctx) { + log.debug("REST request to get a page of Predictions"); + var page = pageRequest.toPage(); + var sort = sortRequest.toSort(); + MultivaluedMap param = uriInfo.getQueryParameters(); + Paged result = new Paged<>(0, 0, 0, 0, new ArrayList<>()); + if (param.containsKey("questionId")) { + List questionId = param.get("questionId"); + result = predictionService.findPredictionByQuestionId(page, Long.parseLong(questionId.get(0))); + } else { + if (ctx.getUserPrincipal().getName() != null) { + var userLogin = Optional.ofNullable(ctx.getUserPrincipal().getName()); + if (!userLogin.isPresent()) { + throw new AccountResourceException("Current user login not found"); + } + var user = User.findOneByLogin(userLogin.get()); + if (!user.isPresent()) { + throw new AccountResourceException("User could not be found"); + + } else if (user.get().authorities.size() >= 1 && user.get().authorities.stream().anyMatch(e1 -> e1.equals(new Authority("ROLE_USER")))) { + //Ici j'ai modif l'autorisation de Admin -> User, je sais pas si c'est bien ou pas mais voila ca me permet mon ajout + result = predictionService.findAll(page); + } else { + return Response.status(403, "Current user cannot access to this resource").build(); + } + } + } + var response = Response.ok().entity(result.content); + response = PaginationUtil.withPaginationInfo(response, uriInfo, result); + return response.build(); + } + + /** + * {@code GET /predictions/:id} : get the "id" prediction. + * + * @param id the id of the predictionDTO to retrieve. + * @return the {@link Response} with status {@code 200 (OK)} and with body the predictionDTO, or with status {@code 404 (Not Found)}. + */ + @GET + @Path("/{id}") + @RolesAllowed({AuthoritiesConstants.USER, AuthoritiesConstants.ADMIN}) + public Response getPrediction(@PathParam("id") Long id, @Context SecurityContext ctx) { + log.debug("REST request to get Prediction : {}", id); + if (!securityService.canAccess(ctx, id, Prediction.class)) { + return Response.status(403, "Current user cannot access to this resource").build(); + } + Optional predictionDTO = predictionService.findOne(id); + return ResponseUtil.wrapOrNotFound(predictionDTO); + } +} diff --git a/src/main/java/fr/istic/web/rest/StudentResponseResource.java b/src/main/java/fr/istic/web/rest/StudentResponseResource.java index d3733ba8..5d7aaba1 100644 --- a/src/main/java/fr/istic/web/rest/StudentResponseResource.java +++ b/src/main/java/fr/istic/web/rest/StudentResponseResource.java @@ -174,7 +174,14 @@ else if (param.containsKey("sheetId") && param.containsKey("questionId")) { result = studentResponseService.findStudentResponsesbysheetIdAndquestionId(page, Long.parseLong("" + sheetId.get(0)), Collections.singletonList( Long.parseLong("" + questionId.get(0)))); - } else { + } + else if (param.containsKey("questionId")) { + List questionId = (List) param.get("questionId"); + + result = studentResponseService.findStudentResponsesbyQuestionId(page, + Long.parseLong("" + questionId.get(0))); + } + else { if (ctx.getUserPrincipal().getName() != null) { var userLogin = Optional diff --git a/src/main/java/fr/istic/web/rest/TemplateResource.java b/src/main/java/fr/istic/web/rest/TemplateResource.java index e3980941..c97bfaeb 100644 --- a/src/main/java/fr/istic/web/rest/TemplateResource.java +++ b/src/main/java/fr/istic/web/rest/TemplateResource.java @@ -3,9 +3,12 @@ import static jakarta.ws.rs.core.UriBuilder.fromPath; import fr.istic.service.TemplateService; +import fr.istic.service.customdto.StudentResponseNote; +import fr.istic.service.customdto.TemplateCaseDTO; import fr.istic.web.rest.errors.BadRequestAlertException; import fr.istic.web.util.HeaderUtil; import fr.istic.web.util.ResponseUtil; +import fr.istic.service.dto.StudentResponseDTO; import fr.istic.service.dto.TemplateDTO; import fr.istic.service.dto.TemplateDTOContent; @@ -13,6 +16,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import fr.istic.domain.StudentResponse; import fr.istic.domain.Template; import fr.istic.security.AuthoritiesConstants; import fr.istic.service.Paged; @@ -147,4 +151,21 @@ public Response getTemplate(@PathParam("id") Long id, @Context SecurityContext c Optional templateDTO = templateService.findOne(id); return ResponseUtil.wrapOrNotFound(templateDTO); } + + @PATCH + @Path(value = "/{id}") + @RolesAllowed({ AuthoritiesConstants.USER, AuthoritiesConstants.ADMIN }) + public Response partialUpdateSR( + @PathParam(value = "id") final Long id, + TemplateCaseDTO tDTO, @Context SecurityContext ctx) { + log.debug("REST request to partial update Template partially : {}, {}", id, tDTO); + + if (!securityService.canAccess(ctx, id, Template.class)) { + return Response.status(403, "Current user cannot access to this ressource").build(); + } + Optional result = templateService.partialUpdate(tDTO, id); + return ResponseUtil.wrapOrNotFound( + result, + HeaderUtil.createEntityUpdateAlert(applicationName, true, ENTITY_NAME, id.toString())); + } } diff --git a/src/main/resources/config/liquibase/fake-data/question_type.csv b/src/main/resources/config/liquibase/fake-data/question_type.csv index b53ec4b4..9da1307a 100644 --- a/src/main/resources/config/liquibase/fake-data/question_type.csv +++ b/src/main/resources/config/liquibase/fake-data/question_type.csv @@ -1,3 +1,4 @@ id;algo_name;endpoint;js_function 2;manual;; 3;QCM;; +4;manuscrit;; diff --git a/src/main/resources/db/migration/V1__Initial_version.sql b/src/main/resources/db/migration/V1__Initial_version.sql index a5950ac2..cbceef12 100644 --- a/src/main/resources/db/migration/V1__Initial_version.sql +++ b/src/main/resources/db/migration/V1__Initial_version.sql @@ -330,6 +330,8 @@ CREATE TABLE `question_type` ( `js_function` varchar(255) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +INSERT INTO question_type (algo_name, endpoint, js_function) VALUES ('manuscrit', '', ''); + -- -------------------------------------------------------- -- @@ -386,6 +388,7 @@ CREATE TABLE `student_response` ( `correctedby_id` bigint DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + -- -------------------------------------------------------- -- @@ -452,6 +455,9 @@ CREATE TABLE `zone` ( `height` int DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + -- -- Index pour les tables déchargées -- @@ -962,6 +968,14 @@ alter table question add column canbenegative bit(1) NOT NULL default 0; alter table question add column mustbeignoreinglobalscale bit(1) NOT NULL default 0; +create table prediction (id bigint not null auto_increment, json_data tinytext, confidence float(53), question_number varchar(255), text varchar(2048), question_id bigint, sheet_id bigint, primary key (id)); +alter table template add column casename bit DEFAULT 1; +alter table course add column archived bit not null DEFAULT 0; + +alter table prediction add constraint FK1xsmwx00gk7213kwfeah9lcjx foreign key (question_id) references question (id); +alter table prediction add constraint FK8nv2hkm3mhxll6be9mwj5402t foreign key (sheet_id) references exam_sheet (id); + + COMMIT; diff --git a/src/main/resources/db/migration/V1__Initial_versionjusdata.sql b/src/main/resources/db/migration/V1__Initial_versionjusdata.sql new file mode 100644 index 00000000..0fbaaa6e --- /dev/null +++ b/src/main/resources/db/migration/V1__Initial_versionjusdata.sql @@ -0,0 +1,38 @@ + +START TRANSACTION; + + + +INSERT INTO `jhi_user` (`id`, `login`, `password_hash`, `first_name`, `last_name`, `email`, `image_url`, `activated`, `lang_key`, `activation_key`, `reset_key`, `created_by`, `created_date`, `reset_date`, `last_modified_by`, `last_modified_date`) VALUES +(1, 'system', '$2a$10$mE.qmcV0mFU5NcKh73TZx.z4ueI/.bDWbj0T1BYyqP481kGGarKLG', 'System', 'System', 'system@localhost', '', b'1', 'fr', NULL, NULL, 'system', NULL, NULL, 'system', NULL), +(2, 'anonymoususer', '$2a$10$j8S5d7Sr7.8VTOYNviDPOeWX8KcYILUVJBsYV83Y5NtECayypx9lO', 'Anonymous', 'User', 'anonymous@localhost', '', b'1', 'fr', NULL, NULL, 'system', NULL, NULL, 'system', NULL), +(3, 'admin', '$2a$10$gSAhZrxMllrbgj/kkK9UceBPpChGWJA7SYIb1Mqo.n5aNLq1/oRrC', 'Administrator', 'Administrator', 'admin@localhost', '', b'1', 'fr', NULL, NULL, 'system', NULL, NULL, 'system', NULL), +(4, 'user', '$2a$10$VEjxo0jq2YG9Rbk2HmX9S.k1uZBGYUHdUcid3g/vfiEl7lwWgOH/K', 'User', 'User', 'user@localhost', '', b'1', 'fr', NULL, NULL, 'system', NULL, NULL, 'system', NULL); + +-- -------------------------------------------------------- + +-- +-- Déchargement des données de la table `jhi_authority` +-- + +INSERT INTO `jhi_authority` (`name`) VALUES +('ROLE_ADMIN'), +('ROLE_USER'); +-- +-- Déchargement des données de la table `jhi_user_authority` +-- + +INSERT INTO `jhi_user_authority` (`user_id`, `authority_name`) VALUES +(1, 'ROLE_ADMIN'), +(3, 'ROLE_ADMIN'), +(1, 'ROLE_USER'), +(3, 'ROLE_USER'), +(4, 'ROLE_USER'); + +alter table question add column randomhorizontalcorrection bit default 0; + + +COMMIT; + + +