-
Notifications
You must be signed in to change notification settings - Fork 6
Add admin HTML editor page and editor routes #187
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Schlaumeier5
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems nice so far, but I still need a few things
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add %[site;title=HTML Editor;content=!FOLLOWS] at the beginning?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also maybe add a text field where you can put in the file name it should be saved as.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Schlaumeier5 Thanks for the review! I’ve added the template header to editor.html and registered a stub POST handler for /editor in PostRequestHandler.java as suggested.
The POST handler currently redirects back to /editor, and can be extended later with the actual save logic.
Please let me know if you’d like any adjustments or a different approach.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Registering post handlers happens in Java code, see here:
Lines 169 to 443 in 49fce0d
| public static void registerHandlers() { | |
| HttpHandler.registerPostRequestHandler("/login", AccessLevel.PUBLIC, (rq) -> { | |
| String username = prepare(rq.getString("username"), false); | |
| // Do not sanitize / url-decode password to allow special characters like % | |
| // This is safe as we calculate the hash value anyways | |
| String password = rq.getString("password"); | |
| // Check login credentials in the database | |
| if (Server.getInstance().isValidUser(username, password)) { | |
| SessionManager manager = Server.getInstance().getWebServer().getSessionManager(); | |
| Session session = manager.getSession(rq); | |
| manager.addSessionUser(session, username); | |
| return PostResponse.ok("Login successful", ContentType.TEXT_PLAIN, rq, session.createSessionCookie()); | |
| } else { | |
| return PostResponse.unauthorized("Wrong credentials!", rq); | |
| } | |
| }); | |
| HttpHandler.registerPostRequestHandler("/add-students", AccessLevel.ADMIN, (rq) -> | |
| handleBatchInsertCSV(rq, "students", ContentType.CSV, t -> { | |
| try { | |
| return Student.generateStudentsFromCSV(t); | |
| } catch (SQLException e) { | |
| throw new IllegalStateException(e); | |
| } | |
| }, PostRequestHandler::csvResult) | |
| ); | |
| HttpHandler.registerPostRequestHandler("/add-teachers", AccessLevel.ADMIN, (rq) -> | |
| handleBatchInsertCSV(rq, "teachers", ContentType.CSV, t -> { | |
| try { | |
| return Teacher.generateTeachersFromCSV(t); | |
| } catch (SQLException e) { | |
| throw new IllegalStateException(e); | |
| } | |
| }, PostRequestHandler::csvResult) | |
| ); | |
| HttpHandler.registerPostRequestHandler("/add-rooms", AccessLevel.ADMIN, (rq) -> | |
| handleBatchInsertCSV(rq, "rooms", ContentType.JSON, t -> { | |
| try { | |
| return Room.generateRoomsFromCSV(t); | |
| } catch (SQLException e) { | |
| throw new IllegalStateException(e); | |
| } | |
| }, Arrays::toString) | |
| ); | |
| HttpHandler.registerPostRequestHandler("/add-teacher", AccessLevel.ADMIN, (rq) -> { | |
| String firstName = prepare(rq.getString("firstName")); | |
| String lastName = prepare(rq.getString("lastName")); | |
| String email = prepare(rq.getString("email"), false); | |
| String password = Teacher.generateRandomPassword(12, (rq.getContentLength() << 4 + firstName.length() + lastName.length()) << 7 + System.currentTimeMillis() * new Random().nextInt()); | |
| Teacher teacher = Teacher.registerTeacher(firstName, lastName, email, password); | |
| return PostResponse.ok(teacher.toString().replace("}", "") + ", \"password\": " + password + "}", ContentType.JSON, rq); | |
| }); | |
| HttpHandler.registerPostRequestHandler("/add-subject", AccessLevel.ADMIN, (rq) -> { | |
| Subject.addSubject(rq.getString("name")); | |
| return PostResponse.redirect("/manage_subjects", rq); | |
| }); | |
| HttpHandler.registerPostRequestHandler("/add-class", AccessLevel.ADMIN, (rq) -> { | |
| SchoolClass.addClass(rq.getString("className"), rq.getInt("grade")); | |
| return PostResponse.redirect("/manage_subjects", rq); | |
| }); | |
| HttpHandler.registerPostRequestHandler("/lpt-file", AccessLevel.ADMIN, (rq) -> { | |
| String file = prepare(rq.getBodyAsString().replaceFirst("file=", "").replace("Â", "")); | |
| Application.getInstance().readFile(file); | |
| return PostResponse.ok("File data stored", ContentType.TEXT_PLAIN, rq); | |
| }); | |
| HttpHandler.registerPostRequestHandler("/subject-request", AccessLevel.USER, (rq) -> { | |
| Student student = rq.getCurrentStudent(); | |
| Subject subject = rq.getSubject(); | |
| SubjectRequest subjectRequest = rq.getSubjectRequest(); | |
| if (student != null) { | |
| if (rq.getBoolean("remove")) { | |
| student.removeSubjectRequest(subject, subjectRequest); | |
| return PostResponse.ok("Removed request", ContentType.TEXT_PLAIN, rq); | |
| } else { | |
| student.addSubjectRequest(subject, subjectRequest); | |
| return PostResponse.ok("Added request", ContentType.TEXT_PLAIN, rq); | |
| } | |
| } else { | |
| return PostResponse.unauthorized(rq); | |
| } | |
| }); | |
| HttpHandler.registerPostRequestHandler("/current-topic", AccessLevel.USER, (rq) -> { | |
| Student student = rq.getCurrentStudent(); | |
| Subject subject = rq.getSubject(); | |
| if (student == null) return PostResponse.unauthorized(rq); | |
| Topic topic = student.getCurrentTopic(subject); | |
| if (topic == null) return PostResponse.badRequest("No current topic for this subject.", rq); | |
| return PostResponse.ok(topic.toJSON(), ContentType.JSON, rq); | |
| }); | |
| HttpHandler.registerPostRequestHandler("/change-current-topic", AccessLevel.TEACHER, (rq) -> { | |
| Student student = rq.getCurrentStudent(); | |
| if (student == null) return PostResponse.unauthorized(rq); | |
| Subject subject = rq.getSubject(); | |
| Topic topic = rq.getTopic(); | |
| if (subject == null || topic == null) return PostResponse.badRequest("Subject or topic id not found", rq); | |
| student.setCurrentTopic(subject, topic); | |
| return PostResponse.ok("Current topic changed successfully", ContentType.TEXT_PLAIN, rq); | |
| }); | |
| HttpHandler.registerPostRequestHandler("/tasks", AccessLevel.USER, (rq) -> { | |
| return PostResponse.ok(JSONUtils.toJSON(rq.getTaskList()), ContentType.JSON, rq); | |
| }); | |
| HttpHandler.registerPostRequestHandler("/update-room", AccessLevel.USER, (rq) -> { | |
| Student student = rq.getCurrentStudent(); | |
| if (student == null) return PostResponse.unauthorized(rq); | |
| Room room = rq.getRoom(); | |
| if (room == null) return PostResponse.badRequest("Room not found", rq); | |
| student.setCurrentRoom(room); | |
| return PostResponse.ok("Changed current room", ContentType.TEXT_PLAIN, rq); | |
| }); | |
| HttpHandler.registerPostRequestHandler("/begin-task", AccessLevel.USER, (rq) -> handleTaskChange(rq, Task.STATUS_IN_PROGRESS)); | |
| HttpHandler.registerPostRequestHandler("/complete-task", AccessLevel.USER, (rq) -> handleTaskChange(rq, Task.STATUS_COMPLETED)); | |
| HttpHandler.registerPostRequestHandler("/cancel-task", AccessLevel.USER, (rq) -> handleTaskChange(rq, Task.STATUS_NOT_STARTED)); | |
| HttpHandler.registerPostRequestHandler("/reopen-task", AccessLevel.USER, (rq) -> handleTaskChange(rq, Task.STATUS_NOT_STARTED)); | |
| HttpHandler.registerPostRequestHandler("/lock-task", AccessLevel.USER, (rq) -> handleTaskChange(rq, Task.STATUS_LOCKED)); | |
| HttpHandler.registerPostRequestHandler("/student-data", AccessLevel.TEACHER, PostRequestHandler::handleStudentGetData); | |
| HttpHandler.registerPostRequestHandler("/rooms", AccessLevel.TEACHER, PostRequestHandler::handleStudentGetData); | |
| HttpHandler.registerPostRequestHandler("/student-subjects", AccessLevel.TEACHER, PostRequestHandler::handleStudentGetData); | |
| HttpHandler.registerPostRequestHandler("/teacher-classes", AccessLevel.ADMIN, PostRequestHandler::handleTeacherGetData); | |
| HttpHandler.registerPostRequestHandler("/teacher-subjects", AccessLevel.ADMIN, PostRequestHandler::handleTeacherGetData); | |
| HttpHandler.registerPostRequestHandler("/student-list", AccessLevel.TEACHER, (rq) -> { | |
| SchoolClass schoolClass = rq.getSchoolClass(); | |
| if (schoolClass == null) return PostResponse.notFound("School class not found", rq); | |
| if (rq.getUser().isTeacher() && !rq.getUser().asTeacher().getClassIds().contains(schoolClass.getId())) | |
| return PostResponse.forbidden("You are not allowed to access this class's student list.", rq); | |
| List<Student> students = schoolClass.getStudents(); | |
| return PostResponse.ok( | |
| JSONUtils.toJSON(students, (student, builder) -> { | |
| builder | |
| .addProperty("id", student.getId()) | |
| .addProperty("name", student.getFirstName() + " " + student.getLastName()) | |
| .addProperty("actionRequired", student.isActionRequired()) | |
| .addProperty("graduationLevel", student.getGraduationLevel()) | |
| .addProperty("room", student.getCurrentRoom() != null ? student.getCurrentRoom().getLabel() : "None"); | |
| if (rq.getJson().containsKey("subjectId") && rq.getSubject() != null) { | |
| Set<SubjectRequest> subjectRequests = student.getCurrentRequests(rq.getSubject()); | |
| builder.addProperty("experiment",subjectRequests.stream().anyMatch(r -> r == SubjectRequest.EXPERIMENT)) | |
| .addProperty("help", subjectRequests.stream().anyMatch(r -> r == SubjectRequest.HELP)) | |
| .addProperty("test", subjectRequests.stream().anyMatch(r -> r == SubjectRequest.EXAM)) | |
| .addProperty("partner", subjectRequests.stream().anyMatch(r -> r == SubjectRequest.PARTNER)); | |
| } | |
| }), | |
| ContentType.JSON, rq | |
| ); | |
| }); | |
| HttpHandler.registerPostRequestHandler("/get-students-by-room", AccessLevel.TEACHER, (rq) -> { | |
| Room room = rq.getRoom(); | |
| List<Student> students = Student.getByRoom(room); | |
| return PostResponse.ok( | |
| JSONUtils.toJSON(students, (student, builder) -> { | |
| builder | |
| .addProperty("id", student.getId()) | |
| .addProperty("name", student.getFirstName() + " " + student.getLastName()) | |
| .addProperty("actionRequired", student.isActionRequired()) | |
| .addProperty("graduationLevel", student.getGraduationLevel()) | |
| .addProperty("room", student.getCurrentRoom() != null ? student.getCurrentRoom().getLabel() : "None"); | |
| if (rq.getJson().containsKey("subjectId") && rq.getSubject() != null) { | |
| Set<SubjectRequest> subjectRequests = student.getCurrentRequests(rq.getSubject()); | |
| builder.addProperty("experiment",subjectRequests.stream().anyMatch(r -> r == SubjectRequest.EXPERIMENT)) | |
| .addProperty("help", subjectRequests.stream().anyMatch(r -> r == SubjectRequest.HELP)) | |
| .addProperty("test", subjectRequests.stream().anyMatch(r -> r == SubjectRequest.EXAM)) | |
| .addProperty("partner", subjectRequests.stream().anyMatch(r -> r == SubjectRequest.PARTNER)); | |
| } | |
| }), | |
| ContentType.JSON, rq | |
| ); | |
| }); | |
| HttpHandler.registerPostRequestHandler("/grade-list", AccessLevel.PUBLIC, (rq) -> { | |
| return PostResponse.ok(JSONUtils.toJSON(rq.getSubject().getGrades()), ContentType.JSON, rq); | |
| }); | |
| HttpHandler.registerPostRequestHandler("/topic-list", AccessLevel.STUDENT, (rq) -> { | |
| return PostResponse.ok(JSONUtils.toJSON(rq.getSubject().getTopics(rq.getInt("grade"))), ContentType.JSON, rq); | |
| }); | |
| HttpHandler.registerPostRequestHandler("/class-subjects", AccessLevel.ADMIN, (rq) -> { | |
| SchoolClass schoolClass = rq.getSchoolClass(); | |
| if (schoolClass == null) return PostResponse.notFound("School class not found", rq); | |
| List<Subject> subjects = schoolClass.getSubjects(); | |
| return PostResponse.ok(JSONUtils.toJSON(subjects, (subject, builder) -> { | |
| builder.addProperty("id", subject.getId()).addProperty("name", subject.getName()); | |
| }), ContentType.JSON, rq); | |
| }); | |
| HttpHandler.registerPostRequestHandler("/search-partner", AccessLevel.USER, (rq) -> { | |
| SchoolClass schoolClass = rq.getSchoolClass(); | |
| Subject subject = rq.getSubject(); | |
| Topic topic = rq.getTopic(); | |
| Student student = rq.getCurrentStudent(); | |
| List<Student> students = Student.getAll().stream() | |
| .filter((s) -> s.getSchoolClass().getGrade() == schoolClass.getGrade()) | |
| .filter((s) -> s.getCurrentTopic(subject).equals(topic) | |
| && s.getSelectedTasks().stream().filter((t) -> t.getTopic().equals(topic)).anyMatch((t) -> student.getSelectedTasks().contains(t)) | |
| && s.getCurrentRequests(subject).stream().anyMatch((r) -> r == SubjectRequest.PARTNER)) | |
| .toList(); | |
| return PostResponse.ok(JSONUtils.toJSON(students, (partner, builder) -> { | |
| builder.addProperty("id", partner.getId()) | |
| .addProperty("name", partner.getFirstName() + " " + partner.getLastName()) | |
| .addProperty("room", partner.getCurrentRoom() != null ? partner.getCurrentRoom().getLabel() : "None"); | |
| }), ContentType.JSON, rq); | |
| }); | |
| HttpHandler.registerPostRequestHandler("/delete-subject", AccessLevel.ADMIN, (rq) -> | |
| handleObjectAction(rq, new TypeToken<Subject>() {}, PostResponse.redirect("/manage_subjects", rq), (subject) -> subject.delete()) | |
| ); | |
| HttpHandler.registerPostRequestHandler("/edit-subject", AccessLevel.ADMIN, (rq) -> | |
| handleObjectAction(rq, new TypeToken<Subject>() {}, PostResponse.redirect("/manage_subjects", rq), (subject) -> subject.edit(prepare(rq.getString("name")))) | |
| ); | |
| HttpHandler.registerPostRequestHandler("/delete-classs", AccessLevel.ADMIN, (rq) -> | |
| handleObjectAction(rq, new TypeToken<SchoolClass>() {}, PostResponse.redirect("/manage_classes", rq), (schoolClass) -> schoolClass.delete()) | |
| ); | |
| HttpHandler.registerPostRequestHandler("/edit-class", AccessLevel.ADMIN, (rq) -> | |
| handleObjectAction(rq, new TypeToken<SchoolClass>() {}, PostResponse.redirect("/manage_classes", rq), (schoolClass) -> schoolClass.edit(prepare(rq.getString("name")), rq.getInt("grade"))) | |
| ); | |
| HttpHandler.registerPostRequestHandler("/add-subject-to-class", AccessLevel.ADMIN, (rq) -> | |
| handleObjectAction(rq, new TypeToken<SchoolClass>() {}, PostResponse.redirect("/class", rq), (schoolClass) -> schoolClass.addSubject(rq.getSubject())) | |
| ); | |
| HttpHandler.registerPostRequestHandler("/add-grade-to-subject", AccessLevel.ADMIN, (rq) -> | |
| handleObjectAction(rq, new TypeToken<Subject>() {}, PostResponse.redirect("/subject", rq), (subject) -> subject.addToGrade(rq.getInt("grade"))) | |
| ); | |
| HttpHandler.registerPostRequestHandler("/delete-grade-from-subject", AccessLevel.ADMIN, (rq) -> | |
| handleObjectAction(rq, new TypeToken<Subject>() {}, PostResponse.redirect("/subject", rq), (subject) -> subject.removeFromGrade(rq.getInt("grade"))) | |
| ); | |
| HttpHandler.registerPostRequestHandler("/delete-topics", AccessLevel.ADMIN, (rq) -> | |
| handleObjectAction(rq, new TypeToken<Subject>() {}, PostResponse.redirect("/subject", rq), (subject) -> subject.getTopics(rq.getInt("grade")).forEach((topic) -> { | |
| try { | |
| topic.delete(); | |
| } catch (SQLException e) { | |
| throw new IllegalStateException(e); | |
| } | |
| })) | |
| ); | |
| HttpHandler.registerPostRequestHandler("/add-class-to-teacher", AccessLevel.ADMIN, (rq) -> | |
| handleObjectAction(rq, new TypeToken<Teacher>() {}, PostResponse.redirect("/teacher", rq), (teacher) -> teacher.addClass(rq.getSchoolClass())) | |
| ); | |
| HttpHandler.registerPostRequestHandler("/add-subject-to-teacher", AccessLevel.ADMIN, (rq) -> | |
| handleObjectAction(rq, new TypeToken<Teacher>() {}, PostResponse.redirect("/teacher", rq), (teacher) -> teacher.addSubject(rq.getSubject())) | |
| ); | |
| HttpHandler.registerPostRequestHandler("/change-graduation-level", AccessLevel.ADMIN, (rq) -> | |
| handleObjectAction(rq, new TypeToken<Student>() {}, PostResponse.ok("Successfully changed graduation level", ContentType.TEXT_PLAIN, rq), (student) -> student.changeGraduationLevel(rq.getInt("graduationLevel"))) | |
| ); | |
| HttpHandler.registerPostRequestHandler("/get-module", AccessLevel.USER, (rq) -> { | |
| return PostResponse.ok(Registry.moduleRegistry().get(rq.getString("key")).toJSON(), ContentType.JSON, rq); | |
| }); | |
| HttpHandler.registerPostRequestHandler("/toggle-module", AccessLevel.ADMIN, (rq) -> { | |
| Registry.moduleRegistry().get(rq.getString("key")).toggle(); | |
| return PostResponse.ok("Module toggled", ContentType.TEXT_PLAIN, rq); | |
| }); | |
| HttpHandler.registerPostRequestHandler("/toggle-module-setting", AccessLevel.ADMIN, (rq) -> { | |
| String[] key = rq.getString("key").split(":"); | |
| Registry.moduleRegistry().get(key[0]).toggleSetting(key[1]); | |
| return PostResponse.ok("Module setting toggled", ContentType.TEXT_PLAIN, rq); | |
| }); | |
| HttpHandler.registerPostRequestHandler("/student-results-csv", AccessLevel.TEACHER, (rq) -> { | |
| Student student = rq.getCurrentStudent(); | |
| if (student == null) return PostResponse.badRequest("There is no current student", rq); | |
| return PostResponse.ok(student.getResultsCSV(), ContentType.CSV, rq); | |
| }); | |
| HttpHandler.registerPostRequestHandler("/completed-tasks", AccessLevel.TEACHER, (rq) -> { | |
| SchoolClass schoolClass = rq.getSchoolClass(); | |
| Subject subject = rq.getSubject(); | |
| if (schoolClass == null) return PostResponse.badRequest("No school class specified", rq); | |
| if (subject == null) return PostResponse.badRequest("No subject specified", rq); | |
| return PostResponse.ok(schoolClass.getCompletedTasksCSV(subject), ContentType.CSV, rq); | |
| }); | |
| HttpHandler.registerPostRequestHandler("/class-results", AccessLevel.TEACHER, (rq) -> { | |
| SchoolClass schoolClass = rq.getSchoolClass(); | |
| Subject subject = rq.getSubject(); | |
| if (schoolClass == null) return PostResponse.badRequest("No school class specified", rq); | |
| if (subject == null) return PostResponse.badRequest("No subject specified", rq); | |
| return PostResponse.ok(schoolClass.getResultsCSV(subject), ContentType.CSV, rq); | |
| }); | |
| HttpHandler.registerPostRequestHandler("/grade-results", AccessLevel.ADMIN, (rq) -> { | |
| int grade = rq.getInt("grade"); | |
| Subject subject = rq.getSubject(); | |
| return PostResponse.ok(SchoolClass.getResultsCSV(grade, subject), ContentType.CSV, rq); | |
| }); | |
| } |
(you can just do a stub method if you do not want to code the logic)
(registering post request handlers this way may be added in a future update, that's why there is "type": "GET")
Schlaumeier5
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice, ty :)
This PR adds a basic HTML editor page for admins.
Changes included:
This sets up the structure for editing templates via the admin UI.