From f289a2a2dc16a84745d4342772b9b916a7441d94 Mon Sep 17 00:00:00 2001 From: polymarv Date: Fri, 16 Feb 2024 16:08:49 +0100 Subject: [PATCH 1/8] added mobile and desktop view for the dashboard --- frontend/assets/images/calendar.svg | 2 +- frontend/lib/components/dashboard_card.dart | 70 +++---- frontend/lib/tabs/home_tab.dart | 197 +++++++++++++------- 3 files changed, 171 insertions(+), 98 deletions(-) diff --git a/frontend/assets/images/calendar.svg b/frontend/assets/images/calendar.svg index aca03825..95d5a910 100644 --- a/frontend/assets/images/calendar.svg +++ b/frontend/assets/images/calendar.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/frontend/lib/components/dashboard_card.dart b/frontend/lib/components/dashboard_card.dart index 5a2c5362..f195109f 100644 --- a/frontend/lib/components/dashboard_card.dart +++ b/frontend/lib/components/dashboard_card.dart @@ -16,45 +16,49 @@ class MyCard extends StatelessWidget { @override Widget build(BuildContext context) { - //double screenWidth = MediaQuery.of(context).size.width; return InkWell( onTap: () { // Add functionality for on click here (redirect to other pages) // redirectPath }, - child: Container( - margin: const EdgeInsets.all(10), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - color: cardColor, - boxShadow: const [ - BoxShadow( - color: Colors.grey, - spreadRadius: 1, - blurRadius: 3, - ) - ], - ), - child: Column( - children: [ - const SizedBox(height: 10), - Text( - title, - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: Colors.black, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 15), + child: Container( + margin: const EdgeInsets.all(10), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(25), + color: cardColor, + boxShadow: const [ + BoxShadow( + color: Colors.grey, + spreadRadius: 1, + blurRadius: 3, + ) + ], + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + title, + style: const TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + textAlign: TextAlign.center, ), - textAlign: TextAlign.center, - ), - const SizedBox(height: 20), - SvgPicture.asset( - imageName, - height: 80, - width: 80, - ), - ], - )), + const SizedBox(height: 5), + Align( + alignment: Alignment.center, + child: SvgPicture.asset( + imageName, + height: 80, + width: 80, + )) + ], + )), + ), ); } } diff --git a/frontend/lib/tabs/home_tab.dart b/frontend/lib/tabs/home_tab.dart index 2b51192c..99497985 100644 --- a/frontend/lib/tabs/home_tab.dart +++ b/frontend/lib/tabs/home_tab.dart @@ -2,21 +2,21 @@ import 'package:flutter/material.dart'; import 'package:frontend/components/dashboard_card.dart'; import 'package:frontend/theme/assets.dart'; -Widget _buildColumn(String title, String value) { +Widget _buildColumn(String title, String value, bool smallDevice) { return Column( children: [ - SizedBox(height: 20), + SizedBox(height: smallDevice ? 10 : 20), Text( title, - style: const TextStyle( - fontSize: 15, + style: TextStyle( + fontSize: smallDevice ? 10 : 17, color: Colors.black, ), textAlign: TextAlign.center, ), Text( value, - style: const TextStyle(fontSize: 30, color: Colors.white), + style: TextStyle(fontSize: smallDevice ? 15 : 30, color: Colors.white), textAlign: TextAlign.center, ), ], @@ -46,77 +46,146 @@ class _HomeTabState extends State { @override Widget build(BuildContext context) { final colors = Theme.of(context).colorScheme; - double screenWidth = MediaQuery.of(context).size.width; - if (loading) { return const Center( child: CircularProgressIndicator(), ); } - return Scaffold( - body: SafeArea( - child: SingleChildScrollView( - child: Center( - child: Container( - constraints: const BoxConstraints(maxWidth: 600), - child: Column( + body: Center( + child: LayoutBuilder( + builder: (context, constraints) { + if (constraints.maxWidth < 600) { + // mobile version + final isSmallPhone = constraints.maxHeight < 570; + return Column( children: [ - GridView.count( - crossAxisCount: 2, - crossAxisSpacing: 10, - shrinkWrap: true, - children: [ - MyCard( - title: 'Events', - cardColor: colors.surfaceVariant, - imageName: events), - MyCard( - title: 'Mensa', - cardColor: colors.surfaceVariant, - imageName: mensa), - MyCard( - title: 'LSF', - cardColor: colors.surfaceVariant, - imageName: calendar, - ), - MyCard( - title: 'Noten', - cardColor: colors.surfaceVariant, - imageName: analytics, + Expanded( + flex: isSmallPhone ? 6 : 3, + child: GridView.count( + crossAxisCount: 2, + shrinkWrap: true, + children: [ + MyCard( + title: 'Events', + cardColor: colors.surfaceVariant, + imageName: events), + MyCard( + title: 'Mensa', + cardColor: colors.surfaceVariant, + imageName: mensa), + MyCard( + title: 'LSF', + cardColor: colors.surfaceVariant, + imageName: calendar, + ), + MyCard( + title: 'Noten', + cardColor: colors.surfaceVariant, + imageName: analytics, + ), + ]), + ), + const SizedBox(height: 10), + Expanded( + flex: 2, + child: Container( + decoration: BoxDecoration( + color: colors.outlineVariant, + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(10), + topRight: Radius.circular(10))), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + _buildColumn( + 'Gegebene Feedbacks', '12', isSmallPhone), + _buildColumn( + 'Absolvierte Quizze', '55', isSmallPhone), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + _buildColumn( + 'Ø Quiz-Position', '4', isSmallPhone), + _buildColumn( + 'Alle Feedbacks ', '1923', isSmallPhone), + ], + ), + ], ), - ], + ), ), - Container( - decoration: BoxDecoration( - color: colors.outlineVariant, - borderRadius: const BorderRadius.all(Radius.circular(20))), - width: screenWidth, - height: 200, - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - _buildColumn('Gegebene Feedbacks', '12'), - _buildColumn('Absolvierte Quizze', '55'), - ], - ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - _buildColumn('Ø Quiz-Position', '4'), - _buildColumn('Alle Feedbacks ', '1923'), - ], - ), - ], + ], + ); + } else { + //desktop version + return Row( + children: [ + Expanded( + flex: 1, + child: GridView.count( + crossAxisCount: 2, + childAspectRatio: 2, + children: [ + MyCard( + title: 'Events', + cardColor: colors.surfaceVariant, + imageName: events), + MyCard( + title: 'Mensa', + cardColor: colors.surfaceVariant, + imageName: mensa), + MyCard( + title: 'LSF', + cardColor: colors.surfaceVariant, + imageName: calendar, + ), + MyCard( + title: 'Noten', + cardColor: colors.surfaceVariant, + imageName: analytics, + ), + ]), + ), + const SizedBox(width: 40), + Expanded( + flex: 1, + child: Container( + decoration: BoxDecoration( + color: colors.outlineVariant, + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(20), + bottomLeft: Radius.circular(20))), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + _buildColumn('Gegebene Feedbacks', '12', false), + _buildColumn('Absolvierte Quizze', '55', false), + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + _buildColumn('Ø Quiz-Position', '4', false), + _buildColumn('Alle Feedbacks ', '1923', false), + ], + ), + ], + ), ), ), ], - ), - ), - ), + ); + } + }, ), ), ); From 7999d3feae2bba9c94e8068a31ab6de9c5572517 Mon Sep 17 00:00:00 2001 From: Johannes Brandenburger <79154528+johannesbrandenburger@users.noreply.github.com> Date: Sun, 18 Feb 2024 11:59:12 +0100 Subject: [PATCH 2/8] courses-user link --- .../mobilelearning/models/Course.java | 31 +++++++++++++++++++ .../mobilelearning/models/auth/User.java | 28 +++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/Course.java b/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/Course.java index c01f2264..e6b93b60 100644 --- a/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/Course.java +++ b/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/Course.java @@ -20,6 +20,7 @@ public class Course implements Serializable { public String name; public String description; public List owners; + public List students; public String key; // feedback @@ -39,6 +40,7 @@ public Course(String name, String description) { this.name = name; this.description = description; this.owners = new ArrayList(); + this.students = new ArrayList(); this.feedbackForms = new ArrayList(); this.feedbackQuestions = new ArrayList(); this.quizForms = new ArrayList(); @@ -89,6 +91,35 @@ public boolean isOwner(User user) { return this.owners.contains(user.getId()); } + // students + public List getStudents() { + return this.students; + } + + public void addStudent(ObjectId student) { + this.students.add(student); + } + + public void removeStudent(ObjectId student) { + this.students.remove(student); + } + + public void setStudents(List students) { + this.students = students; + } + + public boolean isStudent(String userId) { + return this.students.contains(new ObjectId(userId)); + } + + public boolean isStudent(ObjectId userId) { + return this.students.contains(userId); + } + + public boolean isStudent(User user) { + return this.students.contains(user.getId()); + } + // description public String getDescription() { return this.description; diff --git a/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/auth/User.java b/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/auth/User.java index 6a57f6e1..805cea6d 100644 --- a/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/auth/User.java +++ b/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/auth/User.java @@ -12,6 +12,7 @@ public class User { public String username; public String password; public List roles; + public List courses; public User() { } @@ -23,6 +24,7 @@ public User(String email, String name, String username, String password) { this.username = username; this.password = password; this.roles = new ArrayList(); + this.courses = new ArrayList(); // check if email, name and username have ": " in it and if so, only take the part after it if (this.email.contains(": ")) { @@ -129,4 +131,30 @@ public void setId(ObjectId id) { this.id = id; } + // courses + public List getCourses() { + return this.courses; + } + + public void setCourses(List courses) { + this.courses = courses; + } + + public void addCourse(ObjectId course) { + this.courses.add(course); + } + + public void removeCourse(ObjectId course) { + this.courses.remove(course); + } + + public boolean hasCourse(ObjectId course) { + return this.courses.contains(course); + } + + public boolean hasCourse(String courseId) { + return this.courses.contains(new ObjectId(courseId)); + } + + } From bbd6d9521af18c458ac9437d60d374cd897f5294 Mon Sep 17 00:00:00 2001 From: Johannes Brandenburger <79154528+johannesbrandenburger@users.noreply.github.com> Date: Sun, 18 Feb 2024 12:12:23 +0100 Subject: [PATCH 3/8] moodleCourseId --- .../mobilelearning/models/Course.java | 14 ++++++++++++++ .../services/api/models/ApiCourse.java | 5 +++++ 2 files changed, 19 insertions(+) diff --git a/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/Course.java b/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/Course.java index e6b93b60..9f25a8a1 100644 --- a/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/Course.java +++ b/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/Course.java @@ -22,6 +22,7 @@ public class Course implements Serializable { public List owners; public List students; public String key; + public String moodleCourseId; // feedback public List feedbackForms; @@ -46,6 +47,7 @@ public Course(String name, String description) { this.quizForms = new ArrayList(); this.quizQuestions = new ArrayList(); this.key = ""; + this.moodleCourseId = ""; } // id @@ -322,6 +324,14 @@ public String getKey() { return this.key; } + public void setMoodleCourseId(String moodleCourseId) { + this.moodleCourseId = moodleCourseId; + } + + public String getMoodleCourseId() { + return this.moodleCourseId; + } + public static Course fromApiCourse(ApiCourse apiCourse) throws IllegalArgumentException { // validate input @@ -341,6 +351,7 @@ public static Course fromApiCourse(ApiCourse apiCourse) throws IllegalArgumentEx // create course Course course = new Course(apiCourse.getName(), apiCourse.getDescription()); course.setKey(apiCourse.getKey()); + course.setMoodleCourseId(apiCourse.getMoodleCourseId()); // create the feedback forms for (ApiFeedbackForm apiFeedbackForm : apiCourse.getFeedbackForms()) { @@ -375,6 +386,7 @@ public void updateFromApiCourse(ApiCourse apiCourse) { // update course this.setName(apiCourse.getName()); this.setDescription(apiCourse.getDescription()); + this.setMoodleCourseId(apiCourse.getMoodleCourseId()); // update feedback forms for (ApiFeedbackForm apiFeedbackForm : apiCourse.getFeedbackForms()) { @@ -399,4 +411,6 @@ public void updateFromApiCourse(ApiCourse apiCourse) { } } + + } \ No newline at end of file diff --git a/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/api/models/ApiCourse.java b/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/api/models/ApiCourse.java index 07cdfd9e..6cfed40c 100644 --- a/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/api/models/ApiCourse.java +++ b/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/api/models/ApiCourse.java @@ -8,6 +8,7 @@ public class ApiCourse { public List feedbackForms; public List quizForms; public String key; + public String moodleCourseId; public ApiCourse() { } @@ -47,4 +48,8 @@ public List getQuizForms() { public String getKey() { return key; } + + public String getMoodleCourseId() { + return moodleCourseId; + } } From 271707b44ad399585e022993dd81f7126ccee365 Mon Sep 17 00:00:00 2001 From: Johannes Brandenburger <79154528+johannesbrandenburger@users.noreply.github.com> Date: Sun, 18 Feb 2024 13:06:36 +0100 Subject: [PATCH 4/8] updateCourseLinkedToUser --- .../helper/{ => moodle}/MoodleCourse.java | 12 ++-- .../helper/{ => moodle}/MoodleInterface.java | 34 +++++++---- .../{ => moodle}/MoodleTokenResponse.java | 2 +- .../{ => moodle}/MoodleUserIdResponse.java | 2 +- .../mobilelearning/models/auth/User.java | 4 ++ .../repositories/CourseRepository.java | 15 +++++ .../services/CourseService.java | 61 ++++++++++++++++++- .../services/api/ApiService.java | 2 +- .../services/auth/UserService.java | 4 +- 9 files changed, 116 insertions(+), 20 deletions(-) rename backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/{ => moodle}/MoodleCourse.java (89%) rename backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/{ => moodle}/MoodleInterface.java (79%) rename backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/{ => moodle}/MoodleTokenResponse.java (85%) rename backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/{ => moodle}/MoodleUserIdResponse.java (86%) diff --git a/backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/MoodleCourse.java b/backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/moodle/MoodleCourse.java similarity index 89% rename from backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/MoodleCourse.java rename to backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/moodle/MoodleCourse.java index f6bd9a22..1f1ca589 100644 --- a/backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/MoodleCourse.java +++ b/backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/moodle/MoodleCourse.java @@ -1,11 +1,11 @@ -package de.htwg_konstanz.mobilelearning.helper; +package de.htwg_konstanz.mobilelearning.helper.moodle; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; @JsonIgnoreProperties(ignoreUnknown = true) -class MoodleCourse { - public Integer id; +public class MoodleCourse { + public String id; public String fullname; public String shortname; public String summary; @@ -16,7 +16,7 @@ class MoodleCourse { public Integer enddate; public MoodleCourse( - @JsonProperty("id") Integer id, + @JsonProperty("id") String id, @JsonProperty("fullname") String fullname, @JsonProperty("shortname") String shortname, @JsonProperty("summary") String summary, @@ -37,6 +37,10 @@ public MoodleCourse( this.enddate = enddate; } + public String getId() { + return id; + } + @Override public String toString() { return "MoodleCourse{" + diff --git a/backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/MoodleInterface.java b/backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/moodle/MoodleInterface.java similarity index 79% rename from backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/MoodleInterface.java rename to backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/moodle/MoodleInterface.java index 45cc0660..56b219aa 100644 --- a/backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/MoodleInterface.java +++ b/backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/moodle/MoodleInterface.java @@ -1,4 +1,4 @@ -package de.htwg_konstanz.mobilelearning.helper; +package de.htwg_konstanz.mobilelearning.helper.moodle; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; @@ -17,7 +17,7 @@ public class MoodleInterface { private Integer userId; public MoodleInterface(String username, - String password) { + String password) { this.username = username; this.password = password; } @@ -25,20 +25,24 @@ public MoodleInterface(String username, public Boolean login() { ObjectMapper mapper = new ObjectMapper(); - + try { - + // get the token from // https://moodle.htwg-konstanz.de/moodle/login/token.php?username=USERNAME&password=PASSWORD&service=SERVICESHORTNAME CloseableHttpClient client = HttpClients.createDefault(); - HttpGet request = new HttpGet("https://moodle.htwg-konstanz.de/moodle/login/token.php?username=" + this.username + "&password=" + this.password + "&service=moodle_mobile_app"); - MoodleTokenResponse tokenResponse = mapper.readValue(client.execute(request).getEntity().getContent(), MoodleTokenResponse.class); + HttpGet request = new HttpGet("https://moodle.htwg-konstanz.de/moodle/login/token.php?username=" + + this.username + "&password=" + this.password + "&service=moodle_mobile_app"); + MoodleTokenResponse tokenResponse = mapper.readValue(client.execute(request).getEntity().getContent(), + MoodleTokenResponse.class); this.token = tokenResponse.token; - // System.out.println("Successfully logged in as " + this.username + " with token " + this.token.substring(0, 5) + "..."); + // System.out.println("Successfully logged in as " + this.username + " with + // token " + this.token.substring(0, 5) + "..."); // get user id String wsFunction = "core_webservice_get_site_info"; - request = new HttpGet("https://moodle.htwg-konstanz.de/moodle/webservice/rest/server.php?wstoken=" + this.token + "&wsfunction=" + wsFunction + "&moodlewsrestformat=json"); + request = new HttpGet("https://moodle.htwg-konstanz.de/moodle/webservice/rest/server.php?wstoken=" + + this.token + "&wsfunction=" + wsFunction + "&moodlewsrestformat=json"); String response = EntityUtils.toString(client.execute(request).getEntity()); MoodleUserIdResponse userIdResponse = mapper.readValue(response, MoodleUserIdResponse.class); Integer userId = userIdResponse.userid; @@ -47,13 +51,14 @@ public Boolean login() { // get all courses wsFunction = "core_enrol_get_users_courses"; - request = new HttpGet("https://moodle.htwg-konstanz.de/moodle/webservice/rest/server.php?wstoken=" + this.token + "&wsfunction=" + wsFunction + "&userid=" + userId + "&moodlewsrestformat=json"); + request = new HttpGet("https://moodle.htwg-konstanz.de/moodle/webservice/rest/server.php?wstoken=" + + this.token + "&wsfunction=" + wsFunction + "&userid=" + userId + "&moodlewsrestformat=json"); response = EntityUtils.toString(client.execute(request).getEntity()); MoodleCourse[] courses = mapper.readValue(response, MoodleCourse[].class); this.courses = List.of(courses); // System.out.println("Got courses: "); // System.out.println(this.courses); - + } catch (Exception e) { System.out.println("Error while logging into moodle: " + e.getMessage()); return false; @@ -70,6 +75,13 @@ public List getCourses() { return this.courses; } + // if token is not set login first + if (this.token == null) { + if (!this.login()) { + return List.of(); + } + } + ObjectMapper mapper = new ObjectMapper(); try { @@ -88,7 +100,7 @@ public List getCourses() { } catch (Exception e) { System.out.println("Error while getting courses from moodle: " + e.getMessage()); - return null; + return List.of(); } } diff --git a/backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/MoodleTokenResponse.java b/backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/moodle/MoodleTokenResponse.java similarity index 85% rename from backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/MoodleTokenResponse.java rename to backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/moodle/MoodleTokenResponse.java index f3d23b34..16cc8b31 100644 --- a/backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/MoodleTokenResponse.java +++ b/backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/moodle/MoodleTokenResponse.java @@ -1,4 +1,4 @@ -package de.htwg_konstanz.mobilelearning.helper; +package de.htwg_konstanz.mobilelearning.helper.moodle; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/MoodleUserIdResponse.java b/backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/moodle/MoodleUserIdResponse.java similarity index 86% rename from backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/MoodleUserIdResponse.java rename to backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/moodle/MoodleUserIdResponse.java index 65efcb86..cd8127b8 100644 --- a/backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/MoodleUserIdResponse.java +++ b/backend/src/main/java/de/htwg_konstanz/mobilelearning/helper/moodle/MoodleUserIdResponse.java @@ -1,4 +1,4 @@ -package de.htwg_konstanz.mobilelearning.helper; +package de.htwg_konstanz.mobilelearning.helper.moodle; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/auth/User.java b/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/auth/User.java index 805cea6d..64c94730 100644 --- a/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/auth/User.java +++ b/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/auth/User.java @@ -156,5 +156,9 @@ public boolean hasCourse(String courseId) { return this.courses.contains(new ObjectId(courseId)); } + public void clearCourses() { + this.courses.clear(); + } + } diff --git a/backend/src/main/java/de/htwg_konstanz/mobilelearning/repositories/CourseRepository.java b/backend/src/main/java/de/htwg_konstanz/mobilelearning/repositories/CourseRepository.java index 3f0943f1..d5a3290f 100644 --- a/backend/src/main/java/de/htwg_konstanz/mobilelearning/repositories/CourseRepository.java +++ b/backend/src/main/java/de/htwg_konstanz/mobilelearning/repositories/CourseRepository.java @@ -2,10 +2,13 @@ +import java.util.List; + import org.bson.types.ObjectId; import de.htwg_konstanz.mobilelearning.models.Course; import de.htwg_konstanz.mobilelearning.models.Form; +import de.htwg_konstanz.mobilelearning.models.auth.User; import de.htwg_konstanz.mobilelearning.models.feedback.FeedbackForm; import de.htwg_konstanz.mobilelearning.models.quiz.QuizForm; import io.quarkus.mongodb.panache.PanacheMongoRepository; @@ -26,6 +29,10 @@ public Course findByQuizFormConnectCode(Integer connectCode) { return find("quizForms.connectCode", connectCode).firstResult(); } + public Course findByMoodleCourseId(String moodleCourseId) { + return find("moodleCourseId", moodleCourseId).firstResult(); + } + public Course findByFormConnectCode(Integer connectCode) { // TODO: make this more efficient Course course = findByFeedbackFormConnectCode(connectCode); @@ -73,4 +80,12 @@ public Course findByKey(String key) { return find("key", key).firstResult(); } + public List listAllForStudent(User user) { + return find("students", user.getId()).list(); + } + + public List listAllForOwner(User user) { + return find("owners", user.getId()).list(); + } + } diff --git a/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/CourseService.java b/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/CourseService.java index 40257492..68938b32 100644 --- a/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/CourseService.java +++ b/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/CourseService.java @@ -3,11 +3,16 @@ import java.util.List; import org.bson.types.ObjectId; +import org.eclipse.microprofile.jwt.JsonWebToken; import org.jboss.resteasy.reactive.RestPath; +import de.htwg_konstanz.mobilelearning.helper.moodle.MoodleCourse; +import de.htwg_konstanz.mobilelearning.helper.moodle.MoodleInterface; import de.htwg_konstanz.mobilelearning.models.Course; +import de.htwg_konstanz.mobilelearning.models.auth.User; import de.htwg_konstanz.mobilelearning.models.auth.UserRole; import de.htwg_konstanz.mobilelearning.repositories.CourseRepository; +import de.htwg_konstanz.mobilelearning.repositories.UserRepository; import jakarta.annotation.security.RolesAllowed; import jakarta.inject.Inject; import jakarta.ws.rs.GET; @@ -24,6 +29,12 @@ public class CourseService { @Inject private CourseRepository courseRepository; + @Inject + private UserRepository userRepository; + + @Inject + JsonWebToken jwt; + @GET @Produces(MediaType.APPLICATION_JSON) @Path("/{courseId}") @@ -39,7 +50,15 @@ public Course getCourse(@RestPath String courseId) { @Produces(MediaType.APPLICATION_JSON) @RolesAllowed({ UserRole.PROF, UserRole.STUDENT }) public List getCourses() { - List courses = courseRepository.listAll(); + + // update the courses linked to the user + User user = userRepository.findByUsername(jwt.getName()); + if (user == null) { + throw new NotFoundException("User not found."); + } + updateCourseLinkedToUser(user); + + List courses = courseRepository.listAllForStudent(user); courses.forEach(course -> { course.feedbackForms.forEach(form -> { form.questions = List.of(); @@ -106,6 +125,46 @@ public void deleteAllCourses() { courseRepository.deleteAll(); } + public void updateCourseLinkedToUser(User user) { + + // use the moodle interface to get the courses linked to the user + MoodleInterface moodle = new MoodleInterface(user.getUsername(), user.getPassword()); + List moodleCourses = moodle.getCourses(); + + // update the courses linked to the user + List previousCourses = user.getCourses(); + + // case 1: the user was added to a new course (-> add the course to the user and the student to the course) + moodleCourses.forEach(moodleCourse -> { + Course course = courseRepository.findByMoodleCourseId(moodleCourse.getId()); + if (course == null) { + return; + } + if (!user.hasCourse(course.getId())) { + user.addCourse(course.getId()); + course.addStudent(user.getId()); + courseRepository.update(course); + } + }); + + // case 2: the user has a course that is not in the moodle courses (-> remove the course from the user and the student from the course) + List moodleCourseIds = moodleCourses.stream().map(moodleCourse -> moodleCourse.getId()).toList(); + previousCourses.forEach(courseId -> { + Course course = courseRepository.findById(courseId); + if (course == null) { + return; + } + if (!moodleCourseIds.contains(course.getMoodleCourseId())) { + user.removeCourse(courseId); + course.removeStudent(user.getId()); + courseRepository.update(course); + } + }); + + // update the user + userRepository.update(user); + } + // for testing public CourseRepository getCourseRepository() { return courseRepository; diff --git a/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/api/ApiService.java b/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/api/ApiService.java index e992a8dc..00a7878c 100644 --- a/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/api/ApiService.java +++ b/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/api/ApiService.java @@ -66,7 +66,7 @@ public List updateCourses(List courses) { } } - return courseRepository.findAll().list(); + return courseRepository.listAllForOwner(user); } } diff --git a/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/auth/UserService.java b/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/auth/UserService.java index b7a1152e..3cbde27e 100644 --- a/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/auth/UserService.java +++ b/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/auth/UserService.java @@ -128,13 +128,15 @@ public Response login(@RestHeader("Authorization") String authorization) throws userFromLdap.getEmail(), userFromLdap.getName(), userFromLdap.getUsername(), - userFromLdap.getPassword() + password ); newUser.setRoles(userFromLdap.getRoles()); userRepository.persist(newUser); user = newUser; } else { user = existingUser; + user.setPassword(password); + userRepository.update(user); } // return jwt token From 6fe50e5085d84eaa6b7c89dff1ddc16d0f4d8ff3 Mon Sep 17 00:00:00 2001 From: Fabian Date: Sun, 18 Feb 2024 13:25:12 +0100 Subject: [PATCH 5/8] (temp) remove mobile_scanner --- frontend/lib/tabs/live_tab.dart | 48 +++---- .../Flutter/GeneratedPluginRegistrant.swift | 2 - frontend/pubspec.lock | 128 ++++++++++-------- frontend/pubspec.yaml | 2 +- 4 files changed, 97 insertions(+), 83 deletions(-) diff --git a/frontend/lib/tabs/live_tab.dart b/frontend/lib/tabs/live_tab.dart index 7e50a96a..cf6ab430 100644 --- a/frontend/lib/tabs/live_tab.dart +++ b/frontend/lib/tabs/live_tab.dart @@ -5,7 +5,7 @@ import 'package:frontend/global.dart'; import 'package:frontend/theme/assets.dart'; import 'package:frontend/utils.dart'; import 'package:http/http.dart' as http; -import 'package:mobile_scanner/mobile_scanner.dart'; +// import 'package:mobile_scanner/mobile_scanner.dart'; class LiveTab extends StatefulWidget { const LiveTab({super.key}); @@ -57,28 +57,28 @@ class _LiveTabState extends State { } } - void openScanner() { - Navigator.push(context, MaterialPageRoute(builder: (context) { - return Scaffold( - appBar: AppBar(title: const Text('Scanne QR-Code zum Beitreten')), - body: MobileScanner( - onDetect: (capture) { - final List barcodes = capture.barcodes; - for (final barcode in barcodes) { - if (barcode.rawValue != null) { - var qrCodeValue = barcode.rawValue; - Navigator.pop(context, qrCodeValue); - } - } - }, - ), - ); - })).then((qrCodeValue) { - if (qrCodeValue != null) { - joinCourse(qrCodeValue); - } - }); - } + // void openScanner() { + // Navigator.push(context, MaterialPageRoute(builder: (context) { + // return Scaffold( + // appBar: AppBar(title: const Text('Scanne QR-Code zum Beitreten')), + // body: MobileScanner( + // onDetect: (capture) { + // final List barcodes = capture.barcodes; + // for (final barcode in barcodes) { + // if (barcode.rawValue != null) { + // var qrCodeValue = barcode.rawValue; + // Navigator.pop(context, qrCodeValue); + // } + // } + // }, + // ), + // ); + // })).then((qrCodeValue) { + // if (qrCodeValue != null) { + // joinCourse(qrCodeValue); + // } + // }); + // } @override Widget build(BuildContext context) { @@ -189,7 +189,7 @@ class _LiveTabState extends State { padding: const EdgeInsets.only(bottom: 24), child: ElevatedButton( onPressed: () { - openScanner(); + // openScanner(); }, style: ElevatedButton.styleFrom( padding: EdgeInsets.zero, diff --git a/frontend/macos/Flutter/GeneratedPluginRegistrant.swift b/frontend/macos/Flutter/GeneratedPluginRegistrant.swift index f15c78b2..724bb2ac 100644 --- a/frontend/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/frontend/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,10 +5,8 @@ import FlutterMacOS import Foundation -import mobile_scanner import shared_preferences_foundation func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { - MobileScannerPlugin.register(with: registry.registrar(forPlugin: "MobileScannerPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) } diff --git a/frontend/pubspec.lock b/frontend/pubspec.lock index d274f4fb..f9408bfe 100644 --- a/frontend/pubspec.lock +++ b/frontend/pubspec.lock @@ -77,10 +77,10 @@ packages: dependency: transitive description: name: ffi - sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" + sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.2" file: dependency: transitive description: @@ -124,10 +124,10 @@ packages: dependency: "direct main" description: name: http - sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525" + sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938" url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.2.1" http_parser: dependency: transitive description: @@ -136,14 +136,6 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.2" - js: - dependency: transitive - description: - name: js - sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 - url: "https://pub.dev" - source: hosted - version: "0.6.7" jwt_decoder: dependency: "direct main" description: @@ -152,6 +144,30 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.1" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" + url: "https://pub.dev" + source: hosted + version: "10.0.0" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 + url: "https://pub.dev" + source: hosted + version: "2.0.1" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 + url: "https://pub.dev" + source: hosted + version: "2.0.1" lints: dependency: transitive description: @@ -164,42 +180,34 @@ packages: dependency: transitive description: name: matcher - sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.16" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "0.8.0" meta: dependency: transitive description: name: meta - sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e + sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 url: "https://pub.dev" source: hosted - version: "1.10.0" - mobile_scanner: - dependency: "direct main" - description: - name: mobile_scanner - sha256: "190506c3b0cf8a5a3c11e83de8c4f5ef4b6025a06c67d425a03f08129abf20d0" - url: "https://pub.dev" - source: hosted - version: "3.5.6" + version: "1.11.0" path: dependency: transitive description: name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.8.3" + version: "1.9.0" path_parsing: dependency: transitive description: @@ -220,10 +228,10 @@ packages: dependency: transitive description: name: path_provider_platform_interface - sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c" + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" path_provider_windows: dependency: transitive description: @@ -244,18 +252,18 @@ packages: dependency: transitive description: name: platform - sha256: "0a279f0707af40c890e80b1e9df8bb761694c074ba7e1d4ab1bc4b728e200b59" + sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" url: "https://pub.dev" source: hosted - version: "3.1.3" + version: "3.1.4" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8 + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" url: "https://pub.dev" source: hosted - version: "2.1.7" + version: "2.1.8" qr: dependency: transitive description: @@ -292,10 +300,10 @@ packages: dependency: transitive description: name: shared_preferences_foundation - sha256: "7bf53a9f2d007329ee6f3df7268fd498f8373602f943c975598bbb34649b62a7" + sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c" url: "https://pub.dev" source: hosted - version: "2.3.4" + version: "2.3.5" shared_preferences_linux: dependency: transitive description: @@ -308,18 +316,18 @@ packages: dependency: transitive description: name: shared_preferences_platform_interface - sha256: d4ec5fc9ebb2f2e056c617112aa75dcf92fc2e4faaf2ae999caa297473f75d8a + sha256: "22e2ecac9419b4246d7c22bfbbda589e3acf5c0351137d87dd2939d984d37c3b" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.2" shared_preferences_web: dependency: transitive description: name: shared_preferences_web - sha256: "7b15ffb9387ea3e237bb7a66b8a23d2147663d391cafc5c8f37b2e7b4bde5d21" + sha256: d762709c2bbe80626ecc819143013cc820fa49ca5e363620ee20a8b15a3e3daf url: "https://pub.dev" source: hosted - version: "2.2.2" + version: "2.2.1" shared_preferences_windows: dependency: transitive description: @@ -393,26 +401,26 @@ packages: dependency: transitive description: name: vector_graphics - sha256: "0f0c746dd2d6254a0057218ff980fc7f5670fd0fcf5e4db38a490d31eed4ad43" + sha256: "4ac59808bbfca6da38c99f415ff2d3a5d7ca0a6b4809c71d9cf30fba5daf9752" url: "https://pub.dev" source: hosted - version: "1.1.9+1" + version: "1.1.10+1" vector_graphics_codec: dependency: transitive description: name: vector_graphics_codec - sha256: "0edf6d630d1bfd5589114138ed8fada3234deacc37966bec033d3047c29248b7" + sha256: f3247e7ab0ec77dc759263e68394990edc608fb2b480b80db8aa86ed09279e33 url: "https://pub.dev" source: hosted - version: "1.1.9+1" + version: "1.1.10+1" vector_graphics_compiler: dependency: transitive description: name: vector_graphics_compiler - sha256: d24333727332d9bd20990f1483af4e09abdb9b1fc7c3db940b56ab5c42790c26 + sha256: "18489bdd8850de3dd7ca8a34e0c446f719ec63e2bab2e7a8cc66a9028dd76c5a" url: "https://pub.dev" source: hosted - version: "1.1.9+1" + version: "1.1.10+1" vector_math: dependency: transitive description: @@ -421,38 +429,46 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + url: "https://pub.dev" + source: hosted + version: "13.0.0" web: dependency: transitive description: name: web - sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 + sha256: "1d9158c616048c38f712a6646e317a3426da10e884447626167240d45209cbad" url: "https://pub.dev" source: hosted - version: "0.3.0" + version: "0.5.0" web_socket_channel: dependency: "direct main" description: name: web_socket_channel - sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b + sha256: "1d8e795e2a8b3730c41b8a98a2dff2e0fb57ae6f0764a1c46ec5915387d257b2" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.4" win32: dependency: transitive description: name: win32 - sha256: b0f37db61ba2f2e9b7a78a1caece0052564d1bc70668156cf3a29d676fe4e574 + sha256: "464f5674532865248444b4c3daca12bd9bf2d7c47f759ce2617986e7229494a8" url: "https://pub.dev" source: hosted - version: "5.1.1" + version: "5.2.0" xdg_directories: dependency: transitive description: name: xdg_directories - sha256: "589ada45ba9e39405c198fe34eb0f607cddb2108527e658136120892beac46d2" + sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d url: "https://pub.dev" source: hosted - version: "1.0.3" + version: "1.0.4" xml: dependency: transitive description: @@ -462,5 +478,5 @@ packages: source: hosted version: "6.5.0" sdks: - dart: ">=3.2.0 <4.0.0" - flutter: ">=3.16.0" + dart: ">=3.3.0 <4.0.0" + flutter: ">=3.10.0" diff --git a/frontend/pubspec.yaml b/frontend/pubspec.yaml index 45ad537b..4ee2cb2c 100644 --- a/frontend/pubspec.yaml +++ b/frontend/pubspec.yaml @@ -41,7 +41,7 @@ dependencies: shared_preferences: ^2.2.2 jwt_decoder: ^2.0.1 qr_flutter: ^4.1.0 - mobile_scanner: ^3.5.6 + # mobile_scanner: ^3.5.7 dev_dependencies: flutter_test: From ed1b8e9e3cc1c7f6af7d414b12ab4677616e3caa Mon Sep 17 00:00:00 2001 From: Johannes Brandenburger <79154528+johannesbrandenburger@users.noreply.github.com> Date: Sun, 18 Feb 2024 14:15:10 +0100 Subject: [PATCH 6/8] fix deadlock problem --- .../mobilelearning/models/Course.java | 10 +++++-- .../mobilelearning/models/auth/User.java | 10 +++++-- .../services/CourseService.java | 27 +++++++++++-------- 3 files changed, 32 insertions(+), 15 deletions(-) diff --git a/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/Course.java b/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/Course.java index 9f25a8a1..25404015 100644 --- a/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/Course.java +++ b/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/Course.java @@ -99,11 +99,17 @@ public List getStudents() { } public void addStudent(ObjectId student) { - this.students.add(student); + if (!this.students.contains(student)) { + this.students.add(student); + } } public void removeStudent(ObjectId student) { - this.students.remove(student); + try { + this.students.remove(student); + } catch (Exception e) { + System.out.println("not in list"); + } } public void setStudents(List students) { diff --git a/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/auth/User.java b/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/auth/User.java index 64c94730..b50b8aaa 100644 --- a/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/auth/User.java +++ b/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/auth/User.java @@ -141,11 +141,17 @@ public void setCourses(List courses) { } public void addCourse(ObjectId course) { - this.courses.add(course); + if (!this.courses.contains(course)) { + this.courses.add(course); + } } public void removeCourse(ObjectId course) { - this.courses.remove(course); + try { + this.courses.remove(course); + } catch (Exception e) { + System.out.println("not in list"); + } } public boolean hasCourse(ObjectId course) { diff --git a/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/CourseService.java b/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/CourseService.java index 68938b32..1878f2c1 100644 --- a/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/CourseService.java +++ b/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/CourseService.java @@ -1,5 +1,6 @@ package de.htwg_konstanz.mobilelearning.services; +import java.util.ArrayList; import java.util.List; import org.bson.types.ObjectId; @@ -133,33 +134,37 @@ public void updateCourseLinkedToUser(User user) { // update the courses linked to the user List previousCourses = user.getCourses(); - + // case 1: the user was added to a new course (-> add the course to the user and the student to the course) - moodleCourses.forEach(moodleCourse -> { + for (MoodleCourse moodleCourse : moodleCourses) { Course course = courseRepository.findByMoodleCourseId(moodleCourse.getId()); if (course == null) { - return; + continue; } - if (!user.hasCourse(course.getId())) { + if (!user.hasCourse(course.getId()) || !course.isStudent(user.getId())) { user.addCourse(course.getId()); course.addStudent(user.getId()); courseRepository.update(course); } - }); + }; // case 2: the user has a course that is not in the moodle courses (-> remove the course from the user and the student from the course) List moodleCourseIds = moodleCourses.stream().map(moodleCourse -> moodleCourse.getId()).toList(); - previousCourses.forEach(courseId -> { + List coursesToRemove = new ArrayList(); + for (ObjectId courseId : previousCourses) { Course course = courseRepository.findById(courseId); if (course == null) { - return; + continue; } if (!moodleCourseIds.contains(course.getMoodleCourseId())) { - user.removeCourse(courseId); - course.removeStudent(user.getId()); - courseRepository.update(course); + coursesToRemove.add(course); } - }); + }; + for (Course course : coursesToRemove) { + course.removeStudent(user.getId()); + courseRepository.update(course); + user.removeCourse(course.getId()); + } // update the user userRepository.update(user); From feec59111ab32af5b941eb08b8fa136975e457df Mon Sep 17 00:00:00 2001 From: Johannes Brandenburger <79154528+johannesbrandenburger@users.noreply.github.com> Date: Sun, 18 Feb 2024 14:20:16 +0100 Subject: [PATCH 7/8] check if user is student of the course in sockets --- .../services/feedback/socket/LiveFeedbackSocket.java | 6 ++++++ .../mobilelearning/services/quiz/socket/LiveQuizSocket.java | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/feedback/socket/LiveFeedbackSocket.java b/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/feedback/socket/LiveFeedbackSocket.java index 8f6cad77..d161feb5 100644 --- a/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/feedback/socket/LiveFeedbackSocket.java +++ b/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/feedback/socket/LiveFeedbackSocket.java @@ -71,6 +71,12 @@ public void onOpen(Session session, @PathParam("courseId") String courseId, @Pat System.out.println("Form ID: " + formId); System.out.println("User ID: " + userId); + // check if user is student of the course + if (!course.isStudent(userId)) { + System.out.println("User is not a student of the course"); + return; + } + // check if the user is a participant or a owner (by checking if the user is owner of the course) Boolean isOwner = course.isOwner(userId); SocketConnectionType type = isOwner ? SocketConnectionType.OWNER : SocketConnectionType.PARTICIPANT; diff --git a/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/quiz/socket/LiveQuizSocket.java b/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/quiz/socket/LiveQuizSocket.java index 2678c1ae..948ded6f 100644 --- a/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/quiz/socket/LiveQuizSocket.java +++ b/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/quiz/socket/LiveQuizSocket.java @@ -86,6 +86,12 @@ public void onOpen( System.out.println("Form ID: " + formId); System.out.println("User ID: " + userId); + // check if user is student of the course + if (!course.isStudent(userId)) { + System.out.println("User is not a student of the course"); + return; + } + // check if the user is a participant or a owner (by checking if the user is owner of the course) SocketConnectionType type = isOwner ? SocketConnectionType.OWNER : SocketConnectionType.PARTICIPANT; From a6ea034a904400f2865003eafa6fdd1f0adf81d2 Mon Sep 17 00:00:00 2001 From: Johannes Brandenburger <79154528+johannesbrandenburger@users.noreply.github.com> Date: Sun, 18 Feb 2024 14:22:55 +0100 Subject: [PATCH 8/8] mock the special users --- .../htwg_konstanz/mobilelearning/services/CourseService.java | 5 +++++ .../services/feedback/socket/LiveFeedbackSocket.java | 1 - 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/CourseService.java b/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/CourseService.java index 1878f2c1..ebc7bfb7 100644 --- a/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/CourseService.java +++ b/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/CourseService.java @@ -128,6 +128,11 @@ public void deleteAllCourses() { public void updateCourseLinkedToUser(User user) { + // TEMP: mock the special users (Prof, Student, Admin) + if (user.getUsername().equals("Prof") || user.getUsername().equals("Student") || user.getUsername().equals("Admin")) { + return; + } + // use the moodle interface to get the courses linked to the user MoodleInterface moodle = new MoodleInterface(user.getUsername(), user.getPassword()); List moodleCourses = moodle.getCourses(); diff --git a/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/feedback/socket/LiveFeedbackSocket.java b/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/feedback/socket/LiveFeedbackSocket.java index d161feb5..afde7ca3 100644 --- a/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/feedback/socket/LiveFeedbackSocket.java +++ b/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/feedback/socket/LiveFeedbackSocket.java @@ -21,7 +21,6 @@ import de.htwg_konstanz.mobilelearning.repositories.UserRepository; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; -import jakarta.websocket.Endpoint; import jakarta.websocket.OnClose; import jakarta.websocket.OnError; import jakarta.websocket.OnMessage;