Skip to content

Commit

Permalink
CSCEXAM-1210 Restructuring question liberary actions
Browse files Browse the repository at this point in the history
  • Loading branch information
Matti Lupari authored and lupari committed Dec 1, 2023
1 parent d829ef8 commit 0e58000
Show file tree
Hide file tree
Showing 22 changed files with 576 additions and 264 deletions.
31 changes: 31 additions & 0 deletions app/controllers/ExamSectionController.java
Original file line number Diff line number Diff line change
Expand Up @@ -616,4 +616,35 @@ public Result getQuestionDistribution(Long id) {
node.put("distributed", isDistributed);
return ok(Json.toJson(node));
}

@Authenticated
@Restrict({ @Group("TEACHER"), @Group("ADMIN") })
public Result listSections(
Optional<String> filter,
Optional<List<Long>> courseIds,
Optional<List<Long>> examIds,
Optional<List<Long>> tagIds,
Http.Request request
) {
User user = request.attrs().get(Attrs.AUTHENTICATED_USER);
ExpressionList<ExamSection> query = DB.find(ExamSection.class).where();
if (!user.hasRole(Role.Name.ADMIN)) {
query = query.where().eq("creator.id", user.getId());
}
if (filter.isPresent()) {
String condition = String.format("%%%s%%", filter.get());
query = query.ilike("name", condition);
}
if (examIds.isPresent() && !examIds.get().isEmpty()) {
query = query.in("exam.id", examIds.get());
}
if (courseIds.isPresent() && !courseIds.get().isEmpty()) {
query = query.in("exam.course.id", courseIds.get());
}
if (tagIds.isPresent() && !tagIds.get().isEmpty()) {
query = query.in("examSectionQuestions.question.tags.id", tagIds.get());
}
Set<ExamSection> sections = query.findSet();
return ok(sections, PathProperties.parse("(*, creator(id))"));
}
}
4 changes: 2 additions & 2 deletions app/controllers/QuestionController.java
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@ public Result getQuestions(
return ok(Collections.emptySet());
}
PathProperties pp = PathProperties.parse(
"*, modifier(firstName, lastName) questionOwners(id, firstName, lastName, userIdentifier, email), " +
"attachment(id, fileName), options(defaultScore, correctOption, claimChoiceType), tags(name), examSectionQuestions(examSection(exam(state, examActiveEndDate, course(code)))))"
"*, modifier(firstName, lastName), questionOwners(id, firstName, lastName, userIdentifier, email), " +
"attachment(id, fileName), options(defaultScore, correctOption, claimChoiceType), tags(id, name), examSectionQuestions(examSection(exam(state, examActiveEndDate, course(code)))))"
);
Query<Question> query = DB.find(Question.class);
pp.apply(query);
Expand Down
26 changes: 24 additions & 2 deletions app/controllers/TagController.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,19 @@

import be.objectify.deadbolt.java.actions.Group;
import be.objectify.deadbolt.java.actions.Restrict;
import com.fasterxml.jackson.databind.JsonNode;
import controllers.base.BaseController;
import io.ebean.DB;
import io.ebean.ExpressionList;
import io.ebean.text.PathProperties;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.StreamSupport;
import models.Role;
import models.Tag;
import models.User;
import models.questions.Question;
import play.mvc.Http;
import play.mvc.Result;
import sanitizers.Attrs;
Expand All @@ -38,8 +41,8 @@ public class TagController extends BaseController {
@Restrict({ @Group("ADMIN"), @Group("TEACHER") })
public Result listTags(
Optional<String> filter,
Optional<List<Long>> examIds,
Optional<List<Long>> courseIds,
Optional<List<Long>> examIds,
Optional<List<Long>> sectionIds,
Http.Request request
) {
Expand All @@ -62,6 +65,25 @@ public Result listTags(
query = query.in("questions.examSectionQuestions.examSection.id", sectionIds.get());
}
Set<Tag> tags = query.findSet();
return ok(tags, PathProperties.parse("(*, creator(id))"));
return ok(tags, PathProperties.parse("(*, creator(id), questions(id))"));
}

@Restrict({ @Group("ADMIN"), @Group("TEACHER") })
public Result addTagToQuestions(Http.Request request) {
JsonNode body = request.body().asJson();
List<Long> questionIds = StreamSupport
.stream(body.get("questionIds").spliterator(), false)
.map(JsonNode::asLong)
.toList();
Long tagId = body.get("tagId").asLong();
List<Question> questions = DB.find(Question.class).where().idIn(questionIds).findList();
Tag tag = DB.find(Tag.class, tagId);
questions.forEach(question -> {
if (!question.getTags().contains(tag)) {
question.getTags().add(tag);
question.update();
}
});
return ok();
}
}
4 changes: 3 additions & 1 deletion conf/routes
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ DELETE /app/exams/:eid/sections/:sid/questions/:qid controlle
PUT /app/exams/:eid/sections/:sid/reorder controllers.ExamSectionController.reorderSectionQuestions(eid: Long, sid: Long, request: Request)
PUT /app/exams/:eid/reorder controllers.ExamSectionController.reorderSections(eid: Long, request: Request)
GET /app/exams/question/:id/distribution controllers.ExamSectionController.getQuestionDistribution(id: Long)
GET /app/sections controllers.ExamSectionController.listSections(filter: java.util.Optional[String], courseIds: java.util.Optional[LongList], examIds: java.util.Optional[LongList], tagIds: java.util.Optional[LongList], request: Request)

############### Section material interface ###############
GET /app/materials controllers.ExamMaterialController.listMaterials(request: Request)
Expand Down Expand Up @@ -406,7 +407,8 @@ GET /app/availability/:roomId/:date controlle
GET /app/languages controllers.LanguageController.getSupportedLanguages

################# Tag interface ##################
GET /app/tags controllers.TagController.listTags(filter: java.util.Optional[String], examIds: java.util.Optional[LongList], courseIds: java.util.Optional[LongList], sectionIds: java.util.Optional[LongList], request: Request)
GET /app/tags controllers.TagController.listTags(filter: java.util.Optional[String], courseIds: java.util.Optional[LongList], examIds: java.util.Optional[LongList], sectionIds: java.util.Optional[LongList], request: Request)
POST /app/tags/questions controllers.TagController.addTagToQuestions(request: Request)

################# General Settings interface ##################

Expand Down
2 changes: 1 addition & 1 deletion project/plugins.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ resolvers += "Typesafe repository" at "https://repo.typesafe.com/typesafe/releas

addSbtPlugin("org.playframework" % "sbt-plugin" % "3.0.0")

addSbtPlugin("org.playframework" % "sbt-play-ebean" % "8.0.0-M1")
addSbtPlugin("org.playframework" % "sbt-play-ebean" % "8.0.0")

// addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.10.0-RC1")
1 change: 1 addition & 0 deletions ui/src/app/exam/exam.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ export interface ReverseQuestion extends Question {
export interface Tag {
id?: number;
name: string;
questions: Question[];
}

export interface Question {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<div id="sitnet-dialog" role="dialog" aria-modal="true" id="library">
<div class="modal-header">
<div class="student-enroll-dialog-wrap">
<h1 class="student-enroll-title">{{ 'sitnet_transfer_questions' | translate }}</h1>
</div>
</div>
<div class="modal-body">
<div class="question-pick-organisation-box">
<!-- org pick TODO: make a component out of this-->
<div class="row">
<div class="col-12">
<div ngbDropdown #orgPicker="ngbDropdown">
<button ngbDropdownToggle class="btn btn-outline-dark" type="button" id="dropDownToggle">
{{ 'sitnet_faculty_name' | translate }}&nbsp;
<span class="caret"></span>
</button>
<ul ngbDropdownMenu aria-labelledby="dropDownMenu">
<li
ngbDropdownItem
*ngFor="let org of organisations"
role="presentation"
(click)="organisation = org"
>
<a role="menuitem">{{ org.code }}&nbsp;({{ org.name }})</a>
</li>
</ul>
</div>
</div>
</div>
<div class="row align-items-center">
<div class="col-12 mt-2">
<button class="btn green whitetext" [disabled]="!organisation" (click)="transfer()">
{{ 'sitnet_copy' | translate }}
</button>
<span *ngIf="organisation" class="padl10 vertm">({{ organisation.code }})</span>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<div class="student-message-dialog-button-save">
<button class="btn btn-sm btn-primary" (click)="activeModal.close()" autofocus>
{{ 'sitnet_close' | translate }}
</button>
</div>
</div>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import { HttpClient } from '@angular/common/http';
import type { OnInit } from '@angular/core';
import { Component, Input } from '@angular/core';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { TranslateService } from '@ngx-translate/core';
import { ToastrService } from 'ngx-toastr';

Expand All @@ -27,15 +28,20 @@ type Organisation = {

@Component({
selector: 'xm-library-transfer',
templateUrl: './library-transfer.component.html',
templateUrl: './library-transfer-dialog.component.html',
})
export class LibraryTransferComponent implements OnInit {
export class LibraryTransferDialogComponent implements OnInit {
@Input() selections: number[] = [];
organisations: Organisation[] = [];
organisation?: Organisation;
showOrganisationSelection = false;

constructor(private http: HttpClient, private translate: TranslateService, private toast: ToastrService) {}
constructor(
public activeModal: NgbActiveModal,
private http: HttpClient,
private translate: TranslateService,
private toast: ToastrService,
) {}

ngOnInit() {
this.http.get<Organisation[]>('/app/iop/organisations').subscribe((resp) => {
Expand Down
39 changes: 0 additions & 39 deletions ui/src/app/question/library/export/library-transfer.component.html

This file was deleted.

Loading

0 comments on commit 0e58000

Please sign in to comment.