From d44f57ef8f5614e1ad429bfa1aeac64fdcfd9d69 Mon Sep 17 00:00:00 2001 From: Johannes Brandenburger <79154528+johannesbrandenburger@users.noreply.github.com> Date: Mon, 19 Feb 2024 17:12:03 +0100 Subject: [PATCH 1/6] jvm builder --- backend/.dockerignore | 10 ++-- backend/src/main/docker/Dockerfile.jvm | 36 ++++++++++--- .../src/main/resources/application.properties | 2 +- docker-compose.yml | 52 +++++++++++++++++++ frontend/lib/utils.dart | 4 +- nginx/Dockerfile | 5 ++ nginx/default.conf.template | 31 +++++++++++ 7 files changed, 126 insertions(+), 14 deletions(-) create mode 100644 docker-compose.yml create mode 100644 nginx/Dockerfile create mode 100644 nginx/default.conf.template diff --git a/backend/.dockerignore b/backend/.dockerignore index 94810d00..3c6048ae 100644 --- a/backend/.dockerignore +++ b/backend/.dockerignore @@ -1,5 +1,5 @@ -* -!target/*-runner -!target/*-runner.jar -!target/lib/* -!target/quarkus-app/* \ No newline at end of file +# * +# !target/*-runner +# !target/*-runner.jar +# !target/lib/* +# !target/quarkus-app/* \ No newline at end of file diff --git a/backend/src/main/docker/Dockerfile.jvm b/backend/src/main/docker/Dockerfile.jvm index 436b59f6..3fc6d957 100644 --- a/backend/src/main/docker/Dockerfile.jvm +++ b/backend/src/main/docker/Dockerfile.jvm @@ -77,16 +77,40 @@ # accessed directly. (example: "foo.example.com,bar.example.com") # ### -FROM registry.access.redhat.com/ubi8/openjdk-21:1.17 -ENV LANGUAGE='en_US:en' +FROM registry.access.redhat.com/ubi8/openjdk-21:latest as builder + +# copy the pom.xml and all the necessary files (copy .pem files after build) +WORKDIR /project +COPY pom.xml /project/pom.xml +COPY src /project/src +COPY .mvn /project/.mvn +COPY mvnw /project/mvnw + +# build the application +RUN ./mvnw package -DskipTests + +# COPY src/main/resources/*.pem /project/target/quarkus-app/ + +# Start the runner image +FROM registry.access.redhat.com/ubi8/openjdk-21:latest as runner + +ENV LANGUAGE='en_US:en' # We make four distinct layers so if there are application changes the library layers can be re-used -COPY --chown=185 target/quarkus-app/lib/ /deployments/lib/ -COPY --chown=185 target/quarkus-app/*.jar /deployments/ -COPY --chown=185 target/quarkus-app/app/ /deployments/app/ -COPY --chown=185 target/quarkus-app/quarkus/ /deployments/quarkus/ +COPY --from=builder --chown=185 /project/target/quarkus-app/lib/ /deployments/lib/ +COPY --from=builder --chown=185 /project/target/quarkus-app/*.jar /deployments/ +COPY --from=builder --chown=185 /project/target/quarkus-app/app/ /deployments/app/ +COPY --from=builder --chown=185 /project/target/quarkus-app/quarkus/ /deployments/quarkus/ + +# Ensure group permissions are added to the runner +USER root +RUN chgrp -R 0 /deployments && chmod -R g=u /deployments +USER 185 + +# copy the pem files +COPY src/main/resources/*.pem /deployments/quarkus-app/ EXPOSE 8080 USER 185 diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties index 3fe78b7f..7c514fd8 100644 --- a/backend/src/main/resources/application.properties +++ b/backend/src/main/resources/application.properties @@ -2,7 +2,7 @@ quarkus.http.cors=true quarkus.http.cors.origins=* quarkus.http.cors.headers=* quarkus.http.cors.methods=* -quarkus.mongodb.connection-string=mongodb://localhost:27017 +quarkus.mongodb.connection-string=mongodb://host.docker.internal:27019 quarkus.mongodb.database=mobilelearning quarkus.naming.enable-jndi=true diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..730680de --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,52 @@ +version: "3.1" +services: + + # mongo db + mobile-learning-mongo: + image: mongo + container_name: mobile-learning-mongo + environment: + - MONGO_INITDB=mobilelearning + ports: + - 27017:27017 + expose: + - 27017 + + # java quarkus backend + mobile-learning-backend: + build: + context: ./backend + dockerfile: src/main/docker/Dockerfile.jvm + # dockerfile: Dockerfile + container_name: mobile-learning-backend + restart: always + ports: + - 8080:8080 + depends_on: + - mobile-learning-mongo + environment: + - MONGODB_HOST=mobile-learning-mongo + - MONGODB_PORT=27017 + - MONGODB_DATABASE=mobilelearning + volumes: + - ./backend/src/main/resources/privateKey.pem:/deployments/privateKey.pem + - ./backend/src/main/resources/publicKey.pem:/deployments/publicKey.pem + - ./backend/src/main/resources/application.properties:/deployments/application.properties + # extra_hosts: + # - "host.docker.internal:host-gateway" + network_mode: "host" + + # flutter frontend (todo) + + # nginx reverse proxy + mobile-learning-nginx: + build: ./nginx + container_name: mobile-learning-nginx + environment: + - MOBILE_LEARNING_BACKEND_URL=http://localhost:8080 + - MOBILE_LEARNING_FRONTEND_URL=http://localhost:5000 + ports: + - 80:80 + depends_on: + - mobile-learning-backend + network_mode: "host" \ No newline at end of file diff --git a/frontend/lib/utils.dart b/frontend/lib/utils.dart index 3e891d83..0d30f862 100644 --- a/frontend/lib/utils.dart +++ b/frontend/lib/utils.dart @@ -3,7 +3,7 @@ import 'package:flutter/foundation.dart'; String getBackendUrl({String protocol = 'http'}) { // final String? backendUrl = Platform.environment['BACKEND_URL']; // later maybe if (defaultTargetPlatform == TargetPlatform.android) { - return '$protocol://10.0.2.2:8080'; + return '$protocol://10.0.2.2/api'; } - return '$protocol://localhost:8080'; + return '$protocol://localhost/api'; } diff --git a/nginx/Dockerfile b/nginx/Dockerfile new file mode 100644 index 00000000..1524b181 --- /dev/null +++ b/nginx/Dockerfile @@ -0,0 +1,5 @@ +FROM nginx:stable + +COPY ./default.conf.template /etc/nginx/templates/default.conf.template + +EXPOSE 80 \ No newline at end of file diff --git a/nginx/default.conf.template b/nginx/default.conf.template new file mode 100644 index 00000000..99252c89 --- /dev/null +++ b/nginx/default.conf.template @@ -0,0 +1,31 @@ +server { + listen 80; + + location /api { + rewrite /api/(.*) /$1 break; + proxy_pass ${MOBILE_LEARNING_BACKEND_URL}; + proxy_redirect off; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $server_name; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_http_version 1.1; + proxy_connect_timeout 7d; + proxy_send_timeout 7d; + proxy_read_timeout 7d; + } + + location / { + rewrite /(.*) /$1 break; + proxy_pass ${MOBILE_LEARNING_FRONTEND_URL}; + proxy_redirect off; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $server_name; + } + + +} \ No newline at end of file From ce2b64059a69a6acd5ee574601ee75709b9ddab9 Mon Sep 17 00:00:00 2001 From: johannesbrandenburger Date: Mon, 19 Feb 2024 17:26:16 +0100 Subject: [PATCH 2/6] docker internal -> localhost --- backend/src/main/docker/Dockerfile.jvm | 2 -- backend/src/main/resources/application.properties | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/backend/src/main/docker/Dockerfile.jvm b/backend/src/main/docker/Dockerfile.jvm index 3fc6d957..d93a346b 100644 --- a/backend/src/main/docker/Dockerfile.jvm +++ b/backend/src/main/docker/Dockerfile.jvm @@ -91,8 +91,6 @@ COPY mvnw /project/mvnw # build the application RUN ./mvnw package -DskipTests -# COPY src/main/resources/*.pem /project/target/quarkus-app/ - # Start the runner image FROM registry.access.redhat.com/ubi8/openjdk-21:latest as runner diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties index 7c514fd8..3fe78b7f 100644 --- a/backend/src/main/resources/application.properties +++ b/backend/src/main/resources/application.properties @@ -2,7 +2,7 @@ quarkus.http.cors=true quarkus.http.cors.origins=* quarkus.http.cors.headers=* quarkus.http.cors.methods=* -quarkus.mongodb.connection-string=mongodb://host.docker.internal:27019 +quarkus.mongodb.connection-string=mongodb://localhost:27017 quarkus.mongodb.database=mobilelearning quarkus.naming.enable-jndi=true From b17907e9f6b769f1225897768808393263824796 Mon Sep 17 00:00:00 2001 From: johannesbrandenburger Date: Mon, 19 Feb 2024 18:21:28 +0100 Subject: [PATCH 3/6] frontend docker --- docker-compose.yml | 11 ++++++++++- frontend/Dockerfile | 47 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 frontend/Dockerfile diff --git a/docker-compose.yml b/docker-compose.yml index 730680de..fb0f86f9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -36,7 +36,16 @@ services: # - "host.docker.internal:host-gateway" network_mode: "host" - # flutter frontend (todo) + # flutter frontend + mobile-learning-frontend: + build: + context: ./frontend + dockerfile: Dockerfile + ports: + - "5000:80" + container_name: mobile-learning-frontend + restart: always + # nginx reverse proxy mobile-learning-nginx: diff --git a/frontend/Dockerfile b/frontend/Dockerfile new file mode 100644 index 00000000..5f82dc83 --- /dev/null +++ b/frontend/Dockerfile @@ -0,0 +1,47 @@ +# Environemnt to install flutter and build web +FROM debian:latest AS build-env + +# install all needed stuff +RUN apt-get update +RUN apt-get install -y curl git unzip + +# define variables +ARG FLUTTER_SDK=/usr/local/flutter +ARG FLUTTER_VERSION=3.16.7 +ARG APP=/app/ + +#clone flutter +RUN git clone https://github.com/flutter/flutter.git $FLUTTER_SDK +# change dir to current flutter folder and make a checkout to the specific version +RUN cd $FLUTTER_SDK && git fetch && git checkout $FLUTTER_VERSION + +# setup the flutter path as an enviromental variable +ENV PATH="$FLUTTER_SDK/bin:$FLUTTER_SDK/bin/cache/dart-sdk/bin:${PATH}" + +# Start to run Flutter commands +# doctor to see if all was installes ok +RUN flutter doctor -v + +# create folder to copy source code +RUN mkdir $APP +# copy source code to folder +COPY . $APP +# stup new folder as the working directory +WORKDIR $APP + +# Run build: 1 - clean, 2 - pub get, 3 - build web +RUN flutter clean +RUN flutter pub get +RUN flutter build web + +# once heare the app will be compiled and ready to deploy + +# use nginx to deploy +FROM nginx:1.25.2-alpine + +# copy the info of the builded web app to nginx +COPY --from=build-env /app/build/web /usr/share/nginx/html + +# Expose and run nginx but on port 5000 +EXPOSE 80 +CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file From 7fedae9f9e4df716bf124bd2e8f4b19863fc7bb0 Mon Sep 17 00:00:00 2001 From: johannesbrandenburger Date: Mon, 19 Feb 2024 18:26:34 +0100 Subject: [PATCH 4/6] variable backend url in frontend --- frontend/lib/utils.dart | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/frontend/lib/utils.dart b/frontend/lib/utils.dart index 0d30f862..a0113c13 100644 --- a/frontend/lib/utils.dart +++ b/frontend/lib/utils.dart @@ -2,8 +2,19 @@ import 'package:flutter/foundation.dart'; String getBackendUrl({String protocol = 'http'}) { // final String? backendUrl = Platform.environment['BACKEND_URL']; // later maybe - if (defaultTargetPlatform == TargetPlatform.android) { - return '$protocol://10.0.2.2/api'; - } - return '$protocol://localhost/api'; + + // get the current domain (when running in a browser) + final String domain = Uri.base.host; + + // if the domain is localhost, use the local backend + if (domain == 'localhost') { + if (defaultTargetPlatform == TargetPlatform.android) { + return '$protocol://10.0.2.2/8080'; + } + return '$protocol://localhost/8080'; + + // if the domain is not localhost, use the deployed backend + } else { + return '$protocol://$domain/api'; + } } From 6c3c57920624f8ba4a23e279af9131001932adba Mon Sep 17 00:00:00 2001 From: johannesbrandenburger Date: Mon, 19 Feb 2024 18:44:37 +0100 Subject: [PATCH 5/6] add volume to compose mongo --- .gitignore | 1 + docker-compose.yml | 2 ++ 2 files changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 2c2dd04f..0139e2eb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .env personal-playground/ .DS_Store +mongo-data \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index fb0f86f9..fb8f5b6d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,6 +11,8 @@ services: - 27017:27017 expose: - 27017 + volumes: + - ./mongo-data:/data/db # java quarkus backend mobile-learning-backend: From 85aee9960b66842ba05ed5679f9348006b88b817 Mon Sep 17 00:00:00 2001 From: Johannes Brandenburger <79154528+johannesbrandenburger@users.noreply.github.com> Date: Mon, 19 Feb 2024 19:21:30 +0100 Subject: [PATCH 6/6] added range to slider (backend) --- .../models/feedback/FeedbackForm.java | 4 ++- .../models/feedback/FeedbackQuestion.java | 8 +++-- .../services/MockingService.java | 36 +++++++++++++------ .../services/api/models/ApiFeedbackForm.java | 8 ++++- frontend/lib/utils.dart | 6 ++-- 5 files changed, 45 insertions(+), 17 deletions(-) diff --git a/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/feedback/FeedbackForm.java b/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/feedback/FeedbackForm.java index 2c1cb581..759bbdf6 100644 --- a/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/feedback/FeedbackForm.java +++ b/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/feedback/FeedbackForm.java @@ -145,7 +145,9 @@ private static List questionWrappersFromApiFeedbackFormQuestion apiFeedbackQuestion.getDescription(), FeedbackQuestionType.valueOf(apiFeedbackQuestion.getType()), apiFeedbackQuestion.getOptions(), - apiFeedbackQuestion.getKey() + apiFeedbackQuestion.getKey(), + apiFeedbackQuestion.getRangeLow(), + apiFeedbackQuestion.getRangeHigh() ); course.addFeedbackQuestion(feedbackQuestion); diff --git a/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/feedback/FeedbackQuestion.java b/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/feedback/FeedbackQuestion.java index 615245f9..908e8df1 100644 --- a/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/feedback/FeedbackQuestion.java +++ b/backend/src/main/java/de/htwg_konstanz/mobilelearning/models/feedback/FeedbackQuestion.java @@ -8,17 +8,21 @@ public class FeedbackQuestion extends Question { public FeedbackQuestionType type; + public String rangeLow; + public String rangeHigh; public FeedbackQuestion() { } - public FeedbackQuestion(String name, String description, FeedbackQuestionType type, List options, String key) { + public FeedbackQuestion(String name, String description, FeedbackQuestionType type, List options, String key, String rangeLow, String rangeHigh) { super(name, description, options, key); this.type = type; + this.rangeLow = rangeLow; + this.rangeHigh = rangeHigh; } public FeedbackQuestion copy() { - FeedbackQuestion copy = new FeedbackQuestion(this.name, this.description, this.type, this.options, this.key); + FeedbackQuestion copy = new FeedbackQuestion(this.name, this.description, this.type, this.options, this.key, this.rangeLow, this.rangeHigh); copy.id = this.id; return copy; } diff --git a/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/MockingService.java b/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/MockingService.java index 8aa7a7f8..c20b9625 100644 --- a/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/MockingService.java +++ b/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/MockingService.java @@ -45,56 +45,72 @@ public Object addData() { "Wie verständlich war das Thema Kombinatorik?", FeedbackQuestionType.STARS, null, - "F-Q-COMBINATORICS" + "F-Q-COMBINATORICS", + null, + null ); FeedbackQuestion question2 = new FeedbackQuestion( "Kurzweiligkeit", - "Wie kurzweilig war die Vorlesung? (links = langweilig, rechts = kurzweilig)", + "Wie kurzweilig war die Vorlesung?", FeedbackQuestionType.SLIDER, null, - "F-Q-ENTERTAINMENT" + "F-Q-ENTERTAINMENT", + "langweilig", + "spannend" ); FeedbackQuestion question3 = new FeedbackQuestion( "Praxisbezug", - "Wie bewerten Sie den Praxisbezug der Vorlesung? (links = wenig Praxisbezug, rechts = viel Praxisbezug)", + "Wie bewerten Sie den Praxisbezug der Vorlesung?", FeedbackQuestionType.SLIDER, null, - "F-Q-PRACTICALITY" + "F-Q-PRACTICALITY", + "wenig Praxisbezug", + "viel Praxisbezug" ); FeedbackQuestion question4 = new FeedbackQuestion( "Sprachbarriere", "Die Vorlesung wurde auf Englisch gehalten. Wie fanden Sie die Verständlichkeit?", FeedbackQuestionType.SLIDER, null, - "F-Q-ENGLISH" + "F-Q-ENGLISH", + null, + null ); FeedbackQuestion question5 = new FeedbackQuestion( "Prüfungsvorbereitung", "Wenn jetzt direkt die Prüfung wäre, wie gut fühlen Sie sich vorbereitet?", FeedbackQuestionType.STARS, null, - "F-Q-EXAM" + "F-Q-EXAM", + null, + null ); FeedbackQuestion question6 = new FeedbackQuestion( "Technische Mittel", "Wie bewerten Sie die technischen Mittel, die in der Vorlesung verwendet wurden?", FeedbackQuestionType.STARS, null, - "F-Q-TECHNOLOGY" + "F-Q-TECHNOLOGY", + null, + null ); FeedbackQuestion question7 = new FeedbackQuestion( "Schwierigstes Thema", "Welches Thema war für Sie am schwierigsten?", FeedbackQuestionType.SINGLE_CHOICE, List.of("Kombinatorik", "Graphen", "Relationen", "Formale Sprachen", "Endliche Automaten", "Turingmaschinen", "Berechenbarkeit"), - "F-Q-HARDEST-TOPIC" + "F-Q-HARDEST-TOPIC", + null, + null ); FeedbackQuestion question8 = new FeedbackQuestion( "Schwierigstes Thema", "Welches Thema war für Sie am schwierigsten?", FeedbackQuestionType.SINGLE_CHOICE, List.of("Multitenancy", "Microservices", "Cloud Foundry", "Docker", "Kubernetes", "Cloud Native", "Cloud Native Buildpacks"), - "F-Q-HARDEST-TOPIC-2" + "F-Q-HARDEST-TOPIC-2", + null, + null ); // generate a Course diff --git a/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/api/models/ApiFeedbackForm.java b/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/api/models/ApiFeedbackForm.java index 4716a44f..4ef7b2c5 100644 --- a/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/api/models/ApiFeedbackForm.java +++ b/backend/src/main/java/de/htwg_konstanz/mobilelearning/services/api/models/ApiFeedbackForm.java @@ -10,16 +10,20 @@ public static class ApiFeedbackQuestion { public String type; // SLIDER, STARS, FULLTEXT, YES_NO, SINGLE_CHOICE public List options; public String key; + public String rangeLow; + public String rangeHigh; public ApiFeedbackQuestion() { } - public ApiFeedbackQuestion(String name, String description, String type, List options, String key) { + public ApiFeedbackQuestion(String name, String description, String type, List options, String key, String rangeLow, String rangeHigh) { this.name = name; this.description = description; this.type = type; this.options = options; this.key = key; + this.rangeLow = rangeLow; + this.rangeHigh = rangeHigh; } public String getKey() { return this.key; } @@ -29,6 +33,8 @@ public ApiFeedbackQuestion(String name, String description, String type, List getOptions() { return this.options != null ? this.options : List.of(); } + public String getRangeLow() { return this.rangeLow; } + public String getRangeHigh() { return this.rangeHigh; } } public String name; diff --git a/frontend/lib/utils.dart b/frontend/lib/utils.dart index a0113c13..d07e1c13 100644 --- a/frontend/lib/utils.dart +++ b/frontend/lib/utils.dart @@ -9,12 +9,12 @@ String getBackendUrl({String protocol = 'http'}) { // if the domain is localhost, use the local backend if (domain == 'localhost') { if (defaultTargetPlatform == TargetPlatform.android) { - return '$protocol://10.0.2.2/8080'; + return '$protocol://10.0.2.2:8080'; } - return '$protocol://localhost/8080'; + return '$protocol://localhost:8080'; // if the domain is not localhost, use the deployed backend } else { return '$protocol://$domain/api'; - } + } }