- TODO: clear flash part when reclicking button
- TODO: remove console.log(...) messages
+ <%# Submit %>
+ <%# Dummy submit button, the actual submit button is in the modal footer %>
+ <%= f.submit 'Submit', id: 'submit-form-btn', style: 'display: none;'%>
+ <% end %>
diff --git a/config/locales/de.yml b/config/locales/de.yml
index 35bec56b1..56d6c9075 100644
--- a/config/locales/de.yml
+++ b/config/locales/de.yml
@@ -3790,3 +3790,12 @@ de:
name:
taken:
'Eine Watchlist mit diesem Namen existiert bereits.'
+ feedback:
+ title: Titel (optional)
+ comment: Dein Kommentar
+ description_html: >
+
Wir freuen uns über Dein Feedack zu MaMpf, sei es Lob, Kritik oder
+ Anregungen, wie wir als Entwickler:innen-Team die Plattform voranbringen
+ können. Falls Du einen Bug gefunden hast und einen GitHub-Account hast,
+ dann erstelle am besten direkt auf %{mampf-github} ein Issue. Ansonsten
+ gerne auch über dieses Formular.
\ No newline at end of file
diff --git a/config/locales/en.yml b/config/locales/en.yml
index fd3cb8a3f..496b3ee2f 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -3584,3 +3584,12 @@ en:
name:
taken:
'A watchlist with that name already exists.'
+ feedback:
+ title: Title (optional)
+ comment: Your comment
+ description_html: >
+
We are looking forward to your feedback on MaMpf, be it praise, criticism
+ or suggestions on how we as a team of developers can advance the platform.
+ If you have found a bug and have a GitHub account, then create an issue
+ directly on %{github_mampf}. Otherwise, you are welcome to use this
+ form.
\ No newline at end of file
From 56c47411da152693fe07791067bad082b442aa6c Mon Sep 17 00:00:00 2001
From: Splines
Date: Wed, 5 Jul 2023 16:39:30 +0200
Subject: [PATCH 05/57] Add "allow contact via mail" checkbox
A new column was added to the Feedbacks schema.
Note that we did not create a new migration as this is a PR which should
only contain one migration, namely the one for the creation of the whol
Feedback table.
---
app/controllers/feedbacks_controller.rb | 2 +-
app/views/feedbacks/_feedback_form.html.erb | 12 +++++++++++-
config/locales/de.yml | 6 +++++-
config/locales/en.yml | 6 +++++-
db/migrate/20230529080510_create_feedbacks.rb | 1 +
5 files changed, 23 insertions(+), 4 deletions(-)
diff --git a/app/controllers/feedbacks_controller.rb b/app/controllers/feedbacks_controller.rb
index b44c9202c..0aae3628f 100644
--- a/app/controllers/feedbacks_controller.rb
+++ b/app/controllers/feedbacks_controller.rb
@@ -18,6 +18,6 @@ def create
private
def feedback_params
- params.require(:feedback).permit(:title, :feedback)
+ params.require(:feedback).permit(:title, :feedback, :can_contact)
end
end
diff --git a/app/views/feedbacks/_feedback_form.html.erb b/app/views/feedbacks/_feedback_form.html.erb
index 4b5e86e1b..c19b15f70 100644
--- a/app/views/feedbacks/_feedback_form.html.erb
+++ b/app/views/feedbacks/_feedback_form.html.erb
@@ -1,7 +1,8 @@
<%= javascript_include_tag :feedback %>
+
<%# Submit %>
<%# Dummy submit button, the actual submit button is in the modal footer %>
<%= f.submit 'Submit', id: 'submit-form-btn', style: 'display: none;'%>
diff --git a/config/locales/de.yml b/config/locales/de.yml
index 56d6c9075..fb4627545 100644
--- a/config/locales/de.yml
+++ b/config/locales/de.yml
@@ -3791,6 +3791,7 @@ de:
taken:
'Eine Watchlist mit diesem Namen existiert bereits.'
feedback:
+ modal_title: Feedback geben
title: Titel (optional)
comment: Dein Kommentar
description_html: >
@@ -3798,4 +3799,7 @@ de:
Anregungen, wie wir als Entwickler:innen-Team die Plattform voranbringen
können. Falls Du einen Bug gefunden hast und einen GitHub-Account hast,
dann erstelle am besten direkt auf %{mampf-github} ein Issue. Ansonsten
- gerne auch über dieses Formular.
\ No newline at end of file
+ gerne auch über dieses Formular.
+ mail_checkbox: >
+ Erlaube es uns, Dich per E-Mail (%{user_mail}) zu kontaktieren, falls es
+ Rückfragen zu Deinem Feedback gibt.
\ No newline at end of file
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 496b3ee2f..debb79c0d 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -3585,6 +3585,7 @@ en:
taken:
'A watchlist with that name already exists.'
feedback:
+ modal_title: Submit feedback
title: Title (optional)
comment: Your comment
description_html: >
@@ -3592,4 +3593,7 @@ en:
or suggestions on how we as a team of developers can advance the platform.
If you have found a bug and have a GitHub account, then create an issue
directly on %{github_mampf}. Otherwise, you are welcome to use this
- form.
\ No newline at end of file
+ form.
+ mail_checkbox: >
+ Allow us to contact you via email (%{user_mail}) if there are questions
+ about your feedback.
\ No newline at end of file
diff --git a/db/migrate/20230529080510_create_feedbacks.rb b/db/migrate/20230529080510_create_feedbacks.rb
index 5ddc10ab5..40401bdb7 100644
--- a/db/migrate/20230529080510_create_feedbacks.rb
+++ b/db/migrate/20230529080510_create_feedbacks.rb
@@ -3,6 +3,7 @@ def change
create_table :feedbacks do |t|
t.text :title
t.text :feedback
+ t.boolean :can_contact, :default => false
t.references :user, null: false, foreign_key: true
t.timestamps
From 90d044e700b37c2eee3d2afde1f96c22318b5c2a Mon Sep 17 00:00:00 2001
From: Splines
Date: Wed, 5 Jul 2023 16:42:56 +0200
Subject: [PATCH 06/57] Toggle "allow email contact" by default
---
app/views/feedbacks/_feedback_form.html.erb | 1 +
1 file changed, 1 insertion(+)
diff --git a/app/views/feedbacks/_feedback_form.html.erb b/app/views/feedbacks/_feedback_form.html.erb
index c19b15f70..0a8f39c23 100644
--- a/app/views/feedbacks/_feedback_form.html.erb
+++ b/app/views/feedbacks/_feedback_form.html.erb
@@ -30,6 +30,7 @@
<%# Email contact %>
<%= f.check_box :can_contact,
+ checked: 'checked',
class: 'form-check-input' %>
<%= f.label :can_contact,
t('feedback.mail_checkbox', user_mail: @current_user.email),
From cd057ed4656bbbeb11c7161d2eeedf6d17894aa6 Mon Sep 17 00:00:00 2001
From: Splines
Date: Mon, 7 Aug 2023 12:54:01 +0200
Subject: [PATCH 07/57] Improve submit button handler (outsource to function)
---
app/assets/javascripts/feedback.js | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/app/assets/javascripts/feedback.js b/app/assets/javascripts/feedback.js
index 33867995e..0f3369343 100644
--- a/app/assets/javascripts/feedback.js
+++ b/app/assets/javascripts/feedback.js
@@ -1,6 +1,7 @@
-$(document).on('turbolinks:load', () => {
+$(document).on('turbolinks:load', registerSubmitButtonHandler);
+
+function registerSubmitButtonHandler() {
$('#submit-form-btn-outside').click(() => {
- console.log('click');
$('#submit-form-btn').click();
});
-});
+}
From 27e49b9192479789ddf39b44f4f3a73a2a8e5dbc Mon Sep 17 00:00:00 2001
From: Splines
Date: Mon, 7 Aug 2023 12:58:11 +0200
Subject: [PATCH 08/57] Init feedback mailer
Right now just for ourselves, so that we get a plaintext mail with
the feedback of a user.
Env variables were adjusted accordingly, but need to be set manually
in the production environment!
---
app/controllers/feedbacks_controller.rb | 7 ++++++-
app/mailers/feedback_mailer.rb | 15 +++++++++++++++
.../new_user_feedback_email.text.erb | 13 +++++++++++++
config/initializers/default_setting.rb | 13 +++++++------
docker/development/docker-compose.yml | 3 +++
docker/production/docker.env | 2 ++
docker/run_cypress_tests/docker-compose.local.yml | 1 +
docker/run_cypress_tests/docker-compose.yml | 1 +
8 files changed, 48 insertions(+), 7 deletions(-)
create mode 100644 app/mailers/feedback_mailer.rb
create mode 100644 app/views/feedback_mailer/new_user_feedback_email.text.erb
diff --git a/app/controllers/feedbacks_controller.rb b/app/controllers/feedbacks_controller.rb
index 0aae3628f..c8349ef91 100644
--- a/app/controllers/feedbacks_controller.rb
+++ b/app/controllers/feedbacks_controller.rb
@@ -11,7 +11,12 @@ def create
'Something went wrong.'
end
@errors = feedback.errors
- # # redirect_to :root, alert: @errors.full_messages.join(', ')
+ # redirect_to :root, alert: @errors.full_messages.join(', ')
+
+ if successfully_saved
+ FeedbackMailer.with(feedback: feedback).new_user_feedback_email.deliver_later
+ end
+
respond_to(&:js)
end
diff --git a/app/mailers/feedback_mailer.rb b/app/mailers/feedback_mailer.rb
new file mode 100644
index 000000000..9355cfe12
--- /dev/null
+++ b/app/mailers/feedback_mailer.rb
@@ -0,0 +1,15 @@
+class FeedbackMailer < ApplicationMailer
+ default from: DefaultSetting::FEEDBACK_EMAIL
+ layout false
+
+ # Mail to the MaMpf developers including the new feedback of a user.
+ def new_user_feedback_email
+ @feedback = params[:feedback]
+ reply_to_mail = @feedback.can_contact ? @feedback.user.email : ''
+ subject = "Feedback: #{@feedback.title}"
+ mail(to: DefaultSetting::FEEDBACK_EMAIL,
+ subject: subject,
+ content_type: 'text/plain',
+ reply_to: reply_to_mail)
+ end
+end
diff --git a/app/views/feedback_mailer/new_user_feedback_email.text.erb b/app/views/feedback_mailer/new_user_feedback_email.text.erb
new file mode 100644
index 000000000..822815720
--- /dev/null
+++ b/app/views/feedback_mailer/new_user_feedback_email.text.erb
@@ -0,0 +1,13 @@
+# Title
+<%= @feedback.title %>
+
+# Feedback
+<%= @feedback.feedback %>
+
+
+-----
+<% if @feedback.can_contact %>
+Reply to this mail to contact the user.
+<% else %>
+User did not give permission to contact them regarding their feedback, so we cannot reply to this mail.
+<% end %>
diff --git a/config/initializers/default_setting.rb b/config/initializers/default_setting.rb
index ec1aa667f..fa83c1ea7 100644
--- a/config/initializers/default_setting.rb
+++ b/config/initializers/default_setting.rb
@@ -1,10 +1,11 @@
class DefaultSetting
- ERDBEERE_LINK = ENV['ERDBEERE_SERVER']
- MUESLI_LINK = ENV['MUESLI_SERVER']
- PROJECT_EMAIL = ENV['PROJECT_EMAIL']
- PROJECT_NOTIFICATION_EMAIL = ENV['PROJECT_NOTIFICATION_EMAIL']
- BLOG_LINK = ENV['BLOG']
- URL_HOST_SHORT = ENV['URL_HOST_SHORT']
+ ERDBEERE_LINK = ENV.fetch('ERDBEERE_SERVER', nil)
+ MUESLI_LINK = ENV.fetch('MUESLI_SERVER', nil)
+ PROJECT_EMAIL = ENV.fetch('PROJECT_EMAIL', nil)
+ FEEDBACK_EMAIL = ENV.fetch('FEEDBACK_EMAIL', nil)
+ PROJECT_NOTIFICATION_EMAIL = ENV.fetch('PROJECT_NOTIFICATION_EMAIL', nil)
+ BLOG_LINK = ENV.fetch('BLOG', nil)
+ URL_HOST_SHORT = ENV.fetch('URL_HOST_SHORT', nil)
RESEARCHGATE_LINK = 'https://www.researchgate.net/project/MaMpf-Mathematische-Medienplattform'
TOUR_LINK = 'https://mampf.blog/ueber-mampf/'
RESOURCES_LINK = 'https://mampf.blog/ressourcen-fur-editorinnen/'
diff --git a/docker/development/docker-compose.yml b/docker/development/docker-compose.yml
index a5bd44651..922a6f51d 100644
--- a/docker/development/docker-compose.yml
+++ b/docker/development/docker-compose.yml
@@ -77,6 +77,7 @@ services:
ERDBEERE_API: https://erdbeere.mathi.uni-heidelberg.de/api/v1
MUESLI_SERVER: https://muesli.mathi.uni-heidelberg.de
PROJECT_EMAIL: project@localhost
+ FEEDBACK_EMAIL: feedback@localhost
PROJECT_NOTIFICATION_EMAIL: project+notification@localhost
ERROR_EMAIL: mampf-error@mathi.uni-heidelberg.de
INSTANCE_PATH: mampf
@@ -93,6 +94,8 @@ services:
PROJECT_EMAIL_USERNAME: mampf
PROJECT_EMAIL_PASSWORD: mampf
PROJECT_EMAIL_MAILBOX: INBOX
+ FEEDBACK_EMAIL_USERNAME: mampf
+ FEEDBACK_EMAIL_PASSWORD: mampf
BLOG: https://mampf.blog
# uncomment DB_SQL_PRESEED_URL and UPLOADS_PRESEED_URL to enable db preseeding
# DB_SQL_PRESEED_URL: "https://heibox.uni-heidelberg.de/d/6fb4a9d2e7f54d8b9931/files/?p=%2F20220923120841_mampf.sql&dl=1"
diff --git a/docker/production/docker.env b/docker/production/docker.env
index 8070eb0d9..d5dc660b8 100644
--- a/docker/production/docker.env
+++ b/docker/production/docker.env
@@ -20,6 +20,8 @@ IMAPSERVER=mail.mathi.uni-heidelberg.de
PROJECT_EMAIL_USERNAME=creativeusername
PROJECT_EMAIL_PASSWORD=secretsecret
PROJECT_EMAIL_MAILBOX=Other Users/mampf
+FEEDBACK_EMAIL_USERNAME=creative-feedback-username
+FEEDBACK_EMAIL_PASSWORD=creative-feedback-password
# Due to CORS constraints, some urls are proxied to the media server
DOWNLOAD_LOCATION=https://mampf.mathi.uni-heidelberg.de/mediaforward
diff --git a/docker/run_cypress_tests/docker-compose.local.yml b/docker/run_cypress_tests/docker-compose.local.yml
index 7e704f774..83c57390a 100644
--- a/docker/run_cypress_tests/docker-compose.local.yml
+++ b/docker/run_cypress_tests/docker-compose.local.yml
@@ -54,6 +54,7 @@ services:
ERDBEERE_API: https://erdbeere.mathi.uni-heidelberg.de/api/v1
MUESLI_SERVER: https://muesli.mathi.uni-heidelberg.de
PROJECT_EMAIL: project@localhost
+ FEEDBACK_EMAIL: feedback@localhost
PROJECT_NOTIFICATION_EMAIL: project+notification@localhost
MEDIA_FOLDER: mampf
REDIS_URL: redis://redis:6379/1
diff --git a/docker/run_cypress_tests/docker-compose.yml b/docker/run_cypress_tests/docker-compose.yml
index 70603e1cd..e4a8d5139 100644
--- a/docker/run_cypress_tests/docker-compose.yml
+++ b/docker/run_cypress_tests/docker-compose.yml
@@ -58,6 +58,7 @@ services:
ERDBEERE_API: https://erdbeere.mathi.uni-heidelberg.de/api/v1
MUESLI_SERVER: https://muesli.mathi.uni-heidelberg.de
PROJECT_EMAIL: project@localhost
+ FEEBACK_EMAIL: feedback@localhost
PROJECT_NOTIFICATION_EMAIL: project+notification@localhost
MEDIA_FOLDER: mampf
REDIS_URL: redis://redis:6379/1
From 58f438924763707f0fe3a1e928b8ac5dbe3cd2f8 Mon Sep 17 00:00:00 2001
From: Splines
Date: Mon, 7 Aug 2023 12:58:39 +0200
Subject: [PATCH 09/57] Adjust feedback mail in views
---
app/views/feedbacks/_feedback_form.html.erb | 3 ++-
app/views/shared/_footer.html.erb | 2 +-
config/locales/de.yml | 5 +++--
config/locales/en.yml | 3 ++-
4 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/app/views/feedbacks/_feedback_form.html.erb b/app/views/feedbacks/_feedback_form.html.erb
index 0a8f39c23..8a148e029 100644
--- a/app/views/feedbacks/_feedback_form.html.erb
+++ b/app/views/feedbacks/_feedback_form.html.erb
@@ -9,7 +9,8 @@
Wir freuen uns über Dein Feedack zu MaMpf, sei es Lob, Kritik oder
Anregungen, wie wir als Entwickler:innen-Team die Plattform voranbringen
können. Falls Du einen Bug gefunden hast und einen GitHub-Account hast,
- dann erstelle am besten direkt auf %{mampf-github} ein Issue. Ansonsten
- gerne auch über dieses Formular.
+ dann erstelle am besten direkt auf %{github_mampf} ein Issue. Ansonsten
+ gerne auch über dieses Formular oder direkt per %{feedback_mail}.
mail_checkbox: >
Erlaube es uns, Dich per E-Mail (%{user_mail}) zu kontaktieren, falls es
Rückfragen zu Deinem Feedback gibt.
\ No newline at end of file
diff --git a/config/locales/en.yml b/config/locales/en.yml
index ea1da061b..13a5558fa 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -2980,6 +2980,7 @@ en:
course_editors: 'Course Editors'
lecture_editors: 'Additional Event Series Editors'
display_name: 'Display Name'
+ mail_noun: 'email'
email: 'Email address'
preferences: 'Preferences'
language: 'Language'
@@ -3595,7 +3596,7 @@ en:
or suggestions on how we as a team of developers can advance the platform.
If you have found a bug and have a GitHub account, then create an issue
directly on %{github_mampf}. Otherwise, you are welcome to use this
- form.
+ form or send an %{feedback_mail} directly.
mail_checkbox: >
Allow us to contact you via email (%{user_mail}) if there are questions
about your feedback.
\ No newline at end of file
From 8d8e2b2c46c60e33c6d9211a92b1078c60758ba6 Mon Sep 17 00:00:00 2001
From: Splines
Date: Tue, 22 Aug 2023 15:34:43 +0200
Subject: [PATCH 10/57] Implement success/error flow with toast messages
---
app/assets/javascripts/feedback.js | 20 ++++++++++-
app/assets/stylesheets/application.scss | 6 +++-
app/controllers/feedbacks_controller.rb | 11 ++-----
app/views/feedbacks/_feedback.html.erb | 44 +++++++++++++++++++++++++
app/views/feedbacks/create.js.erb | 11 ++++---
app/views/shared/_navbar.html.erb | 19 ++---------
6 files changed, 80 insertions(+), 31 deletions(-)
create mode 100644 app/views/feedbacks/_feedback.html.erb
diff --git a/app/assets/javascripts/feedback.js b/app/assets/javascripts/feedback.js
index 0f3369343..2c5dddea0 100644
--- a/app/assets/javascripts/feedback.js
+++ b/app/assets/javascripts/feedback.js
@@ -1,4 +1,22 @@
-$(document).on('turbolinks:load', registerSubmitButtonHandler);
+$(document).on('turbolinks:load', () => {
+ registerToasts();
+ registerSubmitButtonHandler();
+});
+
+TOAST_OPTIONS = {
+ animation: true,
+ autohide: true,
+ delay: 6000 // autohide after 5s
+};
+
+function registerToasts() {
+ const toastElements = document.querySelectorAll('.toast');
+ console.log(toastElements);
+ const toastList = [...toastElements].map(toast => {
+ new bootstrap.Toast(toast, TOAST_OPTIONS);
+ });
+}
+
function registerSubmitButtonHandler() {
$('#submit-form-btn-outside').click(() => {
diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
index 35f8c0d78..da95deb40 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -302,4 +302,8 @@ a {
&:hover {
text-decoration: underline;
}
-}
\ No newline at end of file
+}
+
+.toast {
+ background-color: white;
+}
diff --git a/app/controllers/feedbacks_controller.rb b/app/controllers/feedbacks_controller.rb
index c8349ef91..9ae31a957 100644
--- a/app/controllers/feedbacks_controller.rb
+++ b/app/controllers/feedbacks_controller.rb
@@ -4,16 +4,9 @@ class FeedbacksController < ApplicationController
def create
feedback = Feedback.new(feedback_params)
feedback.user_id = current_user.id
- successfully_saved = feedback.save
- flash.now[:status_msg] = if successfully_saved
- 'Feedback successfully sent.'
- else
- 'Something went wrong.'
- end
- @errors = feedback.errors
- # redirect_to :root, alert: @errors.full_messages.join(', ')
+ @feedback_success = feedback.save
- if successfully_saved
+ if @feedback_success
FeedbackMailer.with(feedback: feedback).new_user_feedback_email.deliver_later
end
diff --git a/app/views/feedbacks/_feedback.html.erb b/app/views/feedbacks/_feedback.html.erb
new file mode 100644
index 000000000..03ba7a027
--- /dev/null
+++ b/app/views/feedbacks/_feedback.html.erb
@@ -0,0 +1,44 @@
+<%= stylesheet_link_tag 'feedback' %>
+
+<%# Main Modal %>
+
';
},
},
diff --git a/spec/cypress/e2e/courses_spec.cy.js b/spec/cypress/e2e/courses_spec.cy.js
index f8e9cb3e3..833a7bb92 100644
--- a/spec/cypress/e2e/courses_spec.cy.js
+++ b/spec/cypress/e2e/courses_spec.cy.js
@@ -14,7 +14,7 @@ describe("Courses", function () {
it("can add tag to course", () => {
cy.appFactories([
["create", "course"],
- ]).then((records) => {
+ ]).then((_records) => {
cy.visit("/courses/1/edit");
cy.get("#new-tag-button").click();
cy.get("#tag_notions_attributes_0_title").type("Geometrie");
@@ -28,7 +28,7 @@ describe("Courses", function () {
it("can set editor in course", () => {
cy.appFactories([
["create", "course"],
- ]).then((records) => {
+ ]).then((_records) => {
cy.visit("/courses/1/edit");
cy.get("#course_editor_ids-ts-control").click();
cy.get("#course_editor_ids-ts-control").type("ad");
@@ -118,7 +118,7 @@ describe("Courses", function () {
cy.appFactories([
["create_list", "lecture", 6, "released_for_all"],
- ]).then((records) => {
+ ]).then((_records) => {
cy.visit("/main/start");
// cy.get('input[name="search[fulltext]"]').type(records[0][0].title)
cy.contains("Veranstaltungssuche").click();
diff --git a/spec/cypress/e2e/submissions_spec.cy.js b/spec/cypress/e2e/submissions_spec.cy.js
index a59dab957..adcd0b5f6 100644
--- a/spec/cypress/e2e/submissions_spec.cy.js
+++ b/spec/cypress/e2e/submissions_spec.cy.js
@@ -70,7 +70,7 @@ describe("Submissions", () => {
user_id: 1,
lecture_id: 1,
}],
- ]).then((lectures) => {});
+ ]).then((_lectures) => {});
});
it("can create submission", () => {
cy.appFactories([
diff --git a/spec/cypress/e2e/watchlists_spec.cy.js b/spec/cypress/e2e/watchlists_spec.cy.js
index cd12c277f..2513d3787 100644
--- a/spec/cypress/e2e/watchlists_spec.cy.js
+++ b/spec/cypress/e2e/watchlists_spec.cy.js
@@ -62,7 +62,7 @@ describe("Watchlists", () => {
});
it("can create new watchlist in watchlist view", () => {
cy.appFactories([
- ]).then((data) => {
+ ]).then((_data) => {
cy.get("#watchlistsIcon").click();
cy.get("#openNewWatchlistForm").click();
cy.get("#watchlistNameField").type("Lernliste");
@@ -96,7 +96,7 @@ describe("Watchlists", () => {
["create", "watchlist", {
user_id: 1,
}],
- ]).then((data) => {
+ ]).then((_data) => {
cy.visit("watchlists/1");
cy.get("#watchlistVisiblityCheck").should("not.be.checked");
cy.get("#watchlistVisiblityCheck").click();
@@ -109,7 +109,7 @@ describe("Watchlists", () => {
["create", "watchlist", "with_user", {
public: true,
}],
- ]).then((data) => {
+ ]).then((_data) => {
cy.visit("watchlists/1");
cy.get("#watchlistButton").should("exist");
});
@@ -119,7 +119,7 @@ describe("Watchlists", () => {
["create", "watchlist", "with_user", {
public: false,
}],
- ]).then((data) => {
+ ]).then((_data) => {
cy.visit("watchlists/1");
cy.get(":nth-child(3) > .row > .col-12 > :nth-child(2)").contains("Du bist nicht berechtigt").should("exist");
});
@@ -132,7 +132,7 @@ describe("Watchlists", () => {
["create_list", "watchlist_entry", 5, "with_medium", {
watchlist_id: 1,
}],
- ]).then((data) => {
+ ]).then((_data) => {
cy.get("#watchlistsIcon").click();
cy.get("#reverseButton").click();
cy.wait(100);
diff --git a/spec/cypress/plugins/index.js b/spec/cypress/plugins/index.js
index 8dd144a6c..3596c1897 100644
--- a/spec/cypress/plugins/index.js
+++ b/spec/cypress/plugins/index.js
@@ -15,7 +15,7 @@
/**
* @type {Cypress.PluginConfig}
*/
-module.exports = (on, config) => {
+module.exports = (_on, _config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
};
From bc87b65e475849aa48480164f56ecd8eaba35384 Mon Sep 17 00:00:00 2001
From: Splines
Date: Wed, 3 Jan 2024 15:08:33 +0100
Subject: [PATCH 43/57] Get rid of unused widget variable
---
app/javascript/packs/application.js | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/app/javascript/packs/application.js b/app/javascript/packs/application.js
index 9eeaf5b3a..0586df987 100644
--- a/app/javascript/packs/application.js
+++ b/app/javascript/packs/application.js
@@ -17,10 +17,9 @@
import {
WidgetInstance,
} from "friendly-challenge";
-var friendlyChallengeWidgetInstance = WidgetInstance;
document.addEventListener("turbolinks:load", function () {
- var doneCallback, element, options, widget;
+ var doneCallback, element, options;
doneCallback = function (solution) {
console.log(solution);
@@ -40,7 +39,7 @@ document.addEventListener("turbolinks:load", function () {
language: $("#captcha-widget").data("lang"),
};
console.log(options);
- widget = new WidgetInstance(element, options);
+ new WidgetInstance(element, options);
// DO not uncomment, evil
// widget.reset();
}
From a8fc9726fb7611edb37aac3ef677decde8752ba4 Mon Sep 17 00:00:00 2001
From: Splines
Date: Wed, 3 Jan 2024 15:11:07 +0100
Subject: [PATCH 44/57] Fix specs comment tab alignment
---
spec/cypress/e2e/search_spec.cy.js | 22 +++++-----
spec/cypress/e2e/watchlists_spec.cy.js | 58 +++++++++++++-------------
2 files changed, 40 insertions(+), 40 deletions(-)
diff --git a/spec/cypress/e2e/search_spec.cy.js b/spec/cypress/e2e/search_spec.cy.js
index e530b5316..c443b3c79 100644
--- a/spec/cypress/e2e/search_spec.cy.js
+++ b/spec/cypress/e2e/search_spec.cy.js
@@ -12,20 +12,20 @@ describe("Media", () => {
cy.get('input[type="password"]').type("test123456");
cy.get('input[type="submit"]').click();
});
- /* it("can search released media",()=>{
- cy.appFactories([
- ["create","lesson_medium", "with_manuscript","released"],
- ["create","lesson_medium", "with_manuscript"]
- ]).then((records)=>{
- cy.get('#mediaSearchLink').click();
- cy.get('#collapseMediaSearch > .card-body > form > .row > .col-12 > .btn').click();
- cy.get('#media-search-results').get('.col-12 > .card').should('have.length',1);
- });
- }); */
+ /* it("can search released media", () => {
+ cy.appFactories([
+ ["create", "lesson_medium", "with_manuscript", "released"],
+ ["create", "lesson_medium", "with_manuscript"],
+ ]).then((_records) => {
+ cy.get("#mediaSearchLink").click();
+ cy.get("#collapseMediaSearch > .card-body > form > .row > .col-12 > .btn").click();
+ cy.get("#media-search-results").get(".col-12 > .card").should("have.length", 1);
+ });
+ }); */
it("can filter for tags", () => {
cy.appFactories([
["create", "lesson_medium", "with_manuscript", "released", "with_tags"],
- ["create", "lesson_medium", "with_manuscript", "released"],
+ ["create", "lesson_medium", "with_manuscript", "released"],
]).then((records) => {
cy.get("#mediaSearchLink").click();
cy.get("#media_fulltext").type(records[0].description);
diff --git a/spec/cypress/e2e/watchlists_spec.cy.js b/spec/cypress/e2e/watchlists_spec.cy.js
index 2513d3787..4f6cedaa0 100644
--- a/spec/cypress/e2e/watchlists_spec.cy.js
+++ b/spec/cypress/e2e/watchlists_spec.cy.js
@@ -11,35 +11,35 @@ describe("Watchlists", () => {
cy.get('input[type="password"]').type("test123456");
cy.get('input[type="submit"]').click();
});
- // it("can create and add to watchlist in lecture", () => {
- // cy.appFactories([
- // ["create", "lecture_medium", "with_manuscript", "released"],
- // ["create",
- // "lecture_user_join", {
- // user_id: 1,
- // lecture_id: 1
- // }
- // ]
- // ]).then((data) => {
- // cy.visit(`lectures/${data[0].id}`);
- // cy.get('.nav > :nth-child(6) > .nav-link').click();
- // cy.get('div.text-light > .fa-list').click();
- // cy.get('#openNewWatchlistForm').click();
- // cy.get('#watchlistNameField').type('Lernliste');
- // cy.get(100);
- // cy.get('#createWatchlistBtn').click();
- // cy.get('#watchlistEntrySubmitButton').click();
- // cy.wait(100);
- // cy.get('div.text-light > .fa-list').click();
- // cy.get('#watchlistEntrySubmitButton').click();
- // cy.get('.invalid-feedback').should('exist');
- // cy.wait(200);
- // cy.get('.close > span').click();
- // cy.wait(100);
- // cy.get('#watchlistsIcon').click();
- // cy.get('#card-title').should('exist');
- // });
- // });
+ /* it("can create and add to watchlist in lecture", () => {
+ cy.appFactories([
+ ["create", "lecture_medium", "with_manuscript", "released"],
+ ["create",
+ "lecture_user_join", {
+ user_id: 1,
+ lecture_id: 1,
+ },
+ ],
+ ]).then((data) => {
+ cy.visit(`lectures/${data[0].id}`);
+ cy.get(".nav > :nth-child(6) > .nav-link").click();
+ cy.get("div.text-light > .fa-list").click();
+ cy.get("#openNewWatchlistForm").click();
+ cy.get("#watchlistNameField").type("Lernliste");
+ cy.get(100);
+ cy.get("#createWatchlistBtn").click();
+ cy.get("#watchlistEntrySubmitButton").click();
+ cy.wait(100);
+ cy.get("div.text-light > .fa-list").click();
+ cy.get("#watchlistEntrySubmitButton").click();
+ cy.get(".invalid-feedback").should("exist");
+ cy.wait(200);
+ cy.get(".close > span").click();
+ cy.wait(100);
+ cy.get("#watchlistsIcon").click();
+ cy.get("#card-title").should("exist");
+ });
+ }); */
it("can change watchlist", () => {
cy.appFactories([
["create", "watchlist", {
From f636d0fe322b28f02e5d427608cc05f7593cb0a6 Mon Sep 17 00:00:00 2001
From: Splines <37160523+Splines@users.noreply.github.com>
Date: Thu, 11 Jan 2024 19:05:36 +0100
Subject: [PATCH 45/57] Warn about too long GitHub commit messages (#586)
---
.vscode/settings.json | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 21983ff1e..24b00c4b5 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -79,6 +79,12 @@
}
],
//////////////////////////////////////
+ // Git
+ //////////////////////////////////////
+ "git.inputValidation": "warn",
+ "git.inputValidationSubjectLength": 50,
+ "git.inputValidationLength": 72,
+ //////////////////////////////////////
// Spell Checker
//////////////////////////////////////
"cSpell.words": [
From eb9484a8106d15683c5028b55acb0d6798329c29 Mon Sep 17 00:00:00 2001
From: Splines <37160523+Splines@users.noreply.github.com>
Date: Tue, 16 Jan 2024 19:15:51 +0100
Subject: [PATCH 46/57] Fix comment status (#585)
* Reapply first fix for Reader/Media
See discussion on #574 for further details.
Previous PR for this was #576, closed in favor of this one
as this directly branches off the new "dev" branch.
* Correctly show latest post (might be current_user's comment)
* Fix update of unread comments logic in comments controller
* Fix update icon logic and latest post comment
* Simplify latest comment logic
* Improve code comments
* Further improve comments
* Fix wording in comment
* Fix construction of media array & use `.blank?` instead of `.empty?`
---
.../commontator/comments_controller.rb | 51 +++++++++++++------
app/controllers/main_controller.rb | 2 +-
app/controllers/readers_controller.rb | 2 +-
app/models/user.rb | 38 +++++++++++---
app/views/main/comments.html.erb | 4 +-
5 files changed, 70 insertions(+), 27 deletions(-)
diff --git a/app/controllers/commontator/comments_controller.rb b/app/controllers/commontator/comments_controller.rb
index 31058b3da..331919345 100644
--- a/app/controllers/commontator/comments_controller.rb
+++ b/app/controllers/commontator/comments_controller.rb
@@ -71,6 +71,7 @@ def create
Commontator::Subscription.comment_created(@comment)
# The next line constitutes a customization of the original controller
update_unread_status
+ activate_unread_comments_icon_if_necessary
@commontator_page = @commontator_thread.new_comment_page(
@comment.parent_id, @commontator_show_all
@@ -194,9 +195,14 @@ def subscribe_mentioned
end
end
- # This method ensures that the unread_comments flag is updated
- # for users affected by the creation of a newly created comment
- # It constitues a customization
+ # Updates the unread_comments flag for users subscribed to the current thread.
+ # This method should only be called when a new comment was created.
+ #
+ # The originator of the comment does not get the flag set since that user
+ # already knows about the comment; that user has just created it after all.
+ #
+ # (This is a customization of the original controller provided
+ # by the commontator gem.)
def update_unread_status
medium = @commontator_thread.commontable
return unless medium.released.in?(["all", "users", "subscribers"])
@@ -205,22 +211,35 @@ def update_unread_status
relevant_users.where.not(id: current_user.id)
.where(unread_comments: false)
.update(unread_comments: true)
-
- # make sure that the thread associated to this comment is marked as read
- # by the comment creator (unless some other user posted a comment in it
- # that has not yet been read)
- @reader = Reader.find_or_create_by(user: current_user,
- thread: @commontator_thread)
- if unseen_comments?
- @update_icon = true
- return
- end
- @reader.touch
end
- def unseen_comments?
+ # Might activate the flag used in the view to indicate unread comments.
+ # This method should only be called when a new comment was created.
+ # The flag is activated if the current user has not seen all comments
+ # in the thread in which the new comment was created.
+ #
+ # The flag might only be activated, not deactivated since the checks
+ # performed here are not sufficient to determine whether a user has
+ # any unread comments (including those in possibly other threads).
+ #
+ # This method was introduced for one specific edge case:
+ # When the current user A has just created a new comment in a thread,
+ # but in the meantime, another user B has created a comment in the same
+ # thread. User A will not be informed immediately about the new comment
+ # by B since we don't have websockets implemented. Instead, A will be
+ # informed by a visual indicator as soon as A has posted their own comment.
+ #
+ # (This is a customization of the original controller provided
+ # by the commontator gem.)
+ def activate_unread_comments_icon_if_necessary
+ reader = Reader.find_by(user: current_user, thread: @commontator_thread)
+ @update_icon = true if unseen_comments_in_current_thread?(reader)
+ end
+
+ def unseen_comments_in_current_thread?(reader = nil)
@commontator_thread.comments.any? do |c|
- c.creator != current_user && c.created_at > @reader.updated_at
+ not_marked_as_read_in_reader = reader.nil? || c.created_at > reader.updated_at
+ c.creator != current_user && not_marked_as_read_in_reader
end
end
end
diff --git a/app/controllers/main_controller.rb b/app/controllers/main_controller.rb
index 8fa45237c..c7e8d469b 100644
--- a/app/controllers/main_controller.rb
+++ b/app/controllers/main_controller.rb
@@ -26,7 +26,7 @@ def sponsors
end
def comments
- @media_comments = current_user.media_latest_comments
+ @media_comments = current_user.subscribed_media_with_latest_comments_not_by_creator
@media_comments.select! do |m|
(Reader.find_by(user: current_user, thread: m[:thread])
&.updated_at || 1000.years.ago) < m[:latest_comment].created_at &&
diff --git a/app/controllers/readers_controller.rb b/app/controllers/readers_controller.rb
index f276f2989..931b93a45 100644
--- a/app/controllers/readers_controller.rb
+++ b/app/controllers/readers_controller.rb
@@ -9,7 +9,7 @@ def update
@reader = Reader.find_or_create_by(user: current_user,
thread: @thread)
@reader.touch
- @anything_left = current_user.media_latest_comments.any? do |m|
+ @anything_left = current_user.subscribed_media_with_latest_comments_not_by_creator.any? do |m|
(Reader.find_by(user: current_user, thread: m[:thread])
&.updated_at || 1000.years.ago) < m[:latest_comment].created_at
end
diff --git a/app/models/user.rb b/app/models/user.rb
index 7745f2260..40feb6f60 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -549,14 +549,38 @@ def subscribed_commentable_media_with_comments
.select { |m| m.commontator_thread.comments.any? }
end
- def media_latest_comments
- media = subscribed_commentable_media_with_comments
- .map do |m|
- { medium: m,
- thread: m.commontator_thread,
- latest_comment: m.commontator_thread
- .comments.max_by(&:created_at) }
+ # Returns the media that the user has subscribed to and that have been
+ # commented on by somebody else (not by the current user). The order is
+ # given by the time of the latest comment by somebody else.
+ #
+ # Media that have not been commented on by somebody else than the current user,
+ # are not returned (!).
+ #
+ # For each medium, the following information is stored:
+ # - the medium itself
+ # - the thread of the medium
+ # - the latest comment by somebody else than the current user
+ # - the latest comment by any user (which might include the current user)
+ def subscribed_media_with_latest_comments_not_by_creator
+ media = []
+
+ subscribed_commentable_media_with_comments.each do |m|
+ thread = m.commontator_thread
+ comments = thread.comments
+ next if comments.blank?
+
+ comments_not_by_creator = comments.reject { |c| c.creator == self }
+ next if comments_not_by_creator.blank?
+
+ latest_comment = comments_not_by_creator.max_by(&:created_at)
+ latest_comment_by_any_user = comments.max_by(&:created_at)
+
+ media << { medium: m,
+ thread: thread,
+ latest_comment: latest_comment,
+ latest_comment_by_any_user: latest_comment_by_any_user }
end
+
media.sort_by { |x| x[:latest_comment].created_at }.reverse
end
diff --git a/app/views/main/comments.html.erb b/app/views/main/comments.html.erb
index 13e122bad..22f6e5ad4 100644
--- a/app/views/main/comments.html.erb
+++ b/app/views/main/comments.html.erb
@@ -68,8 +68,8 @@
From 475fc0483821e89df8f2c1f73772c11b71920893 Mon Sep 17 00:00:00 2001
From: Splines <37160523+Splines@users.noreply.github.com>
Date: Wed, 17 Jan 2024 23:21:59 +0100
Subject: [PATCH 47/57] Migrate `unread_comments` flag (fix inconsistencies)
(#587)
* Add dummy migration
* Implement migration for unread comment flag
* Remove unnecessary comment
* Declare migration as not idempotent
* Use array.length instead of counting
* Throw error to prevent revert of migration
* Fix severe flaws in unread comments migration
* Simplify Reader retrieval
* Use the more explicit `.nil?` method
* Update migration date
* Fix annoying bug: don't use `.select!` but `.select`
* Polish migration
e.g. update comment, more suitable name for the method etc.
* Rename method according to #585
---
...000_fix_unread_comments_inconsistencies.rb | 56 +++++++++++++++++++
db/schema.rb | 2 +-
2 files changed, 57 insertions(+), 1 deletion(-)
create mode 100644 db/migrate/20240116180000_fix_unread_comments_inconsistencies.rb
diff --git a/db/migrate/20240116180000_fix_unread_comments_inconsistencies.rb b/db/migrate/20240116180000_fix_unread_comments_inconsistencies.rb
new file mode 100644
index 000000000..3392da3dc
--- /dev/null
+++ b/db/migrate/20240116180000_fix_unread_comments_inconsistencies.rb
@@ -0,0 +1,56 @@
+# Fixes the unread_comments flag for all users. Unintended behavior was
+# introduced in pull request #515. Migration introduced in #587.
+# Behavior fixed in #585.
+#
+# This migration is generally *not* idempotent since users might have interacted
+# with the website since the migration was run and thus they will probably have
+# different unread comments flags as the ones at the time of the migration.
+#
+# This migration is not reversible as we don't store the previous state of
+# the unread_comments flag.
+class FixUnreadCommentsInconsistencies < ActiveRecord::Migration[7.0]
+ def up
+ num_fixed_users = 0
+
+ User.find_each do |user|
+ had_user_unread_comments = user.unread_comments # boolean
+ has_user_unread_comments = user_unread_comments?(user)
+
+ has_flag_changed = (had_user_unread_comments != has_user_unread_comments)
+ user.update(unread_comments: has_user_unread_comments) if has_flag_changed
+ num_fixed_users += 1 if has_flag_changed
+ end
+
+ Rails.logger.debug { "Ran through #{User.count} users (unread comments flag)" }
+ Rails.logger.debug { "Fixed #{num_fixed_users} users (unread comments flag)" }
+ end
+
+ # Checks and returns whether the user has unread comments.
+ def user_unread_comments?(user)
+ # Check for unread comments -- directly via Reader
+ readers = Reader.where(user: user)
+ readers.each do |reader|
+ thread = Commontator::Thread.find_by(id: reader.thread_id)
+ next if thread.nil?
+
+ latest_thread_comment_by_any_user = thread.comments.max_by(&:created_at)
+ next if latest_thread_comment_by_any_user.blank?
+
+ latest_thread_comment_time = latest_thread_comment_by_any_user.created_at
+ has_user_unread_comments = reader.updated_at < latest_thread_comment_time
+
+ return true if has_user_unread_comments
+ end
+
+ # User might still have unread comments but no related Reader objects
+ # -> Check for unread comments -- via Media
+ unseen_media = user.subscribed_media_with_latest_comments_not_by_creator.select do |m|
+ m[:medium].visible_for_user?(user)
+ end
+ unseen_media.present?
+ end
+
+ def down
+ raise ActiveRecord::IrreversibleMigration
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 923aed6fb..0eb8c6842 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema[7.0].define(version: 2023_11_01_100015) do
+ActiveRecord::Schema[7.0].define(version: 2024_01_16_180000) do
# These are extensions that must be enabled in order to support this database
enable_extension "pgcrypto"
enable_extension "plpgsql"
From 92d48d4d03f1393fb017356384afee0b8cdb6ace Mon Sep 17 00:00:00 2001
From: Splines <37160523+Splines@users.noreply.github.com>
Date: Fri, 19 Jan 2024 16:06:36 +0100
Subject: [PATCH 48/57] Use `warn` log level for migration (#588)
---
.../20240116180000_fix_unread_comments_inconsistencies.rb | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/db/migrate/20240116180000_fix_unread_comments_inconsistencies.rb b/db/migrate/20240116180000_fix_unread_comments_inconsistencies.rb
index 3392da3dc..74ef88755 100644
--- a/db/migrate/20240116180000_fix_unread_comments_inconsistencies.rb
+++ b/db/migrate/20240116180000_fix_unread_comments_inconsistencies.rb
@@ -21,8 +21,8 @@ def up
num_fixed_users += 1 if has_flag_changed
end
- Rails.logger.debug { "Ran through #{User.count} users (unread comments flag)" }
- Rails.logger.debug { "Fixed #{num_fixed_users} users (unread comments flag)" }
+ Rails.logger.warn { "Ran through #{User.count} users (unread comments flag)" }
+ Rails.logger.warn { "Fixed #{num_fixed_users} users (unread comments flag)" }
end
# Checks and returns whether the user has unread comments.
From ca14be21b20de125052d8fbffd7d147a3b126d99 Mon Sep 17 00:00:00 2001
From: Splines
Date: Thu, 25 Jan 2024 20:08:09 +0100
Subject: [PATCH 49/57] Fix linting in feedback.js
---
app/assets/javascripts/feedback.js | 83 +++++++++++++++---------------
1 file changed, 42 insertions(+), 41 deletions(-)
diff --git a/app/assets/javascripts/feedback.js b/app/assets/javascripts/feedback.js
index 1430e54ac..57d243602 100644
--- a/app/assets/javascripts/feedback.js
+++ b/app/assets/javascripts/feedback.js
@@ -1,57 +1,58 @@
-$(document).on('turbolinks:load', () => {
- if (!shouldRegisterFeedback()) {
- return;
- }
- registerToasts();
- registerSubmitButtonHandler();
- registerFeedbackBodyValidator();
+$(document).on("turbolinks:load", () => {
+ if (!shouldRegisterFeedback()) {
+ return;
+ }
+ registerToasts();
+ registerSubmitButtonHandler();
+ registerFeedbackBodyValidator();
});
-SUBMIT_FEEDBACK_ID = '#submit-feedback';
+const SUBMIT_FEEDBACK_ID = "#submit-feedback";
-TOAST_OPTIONS = {
- animation: true,
- autohide: true,
- delay: 6000 // autohide after ... milliseconds
+const TOAST_OPTIONS = {
+ animation: true,
+ autohide: true,
+ delay: 6000, // autohide after ... milliseconds
};
function shouldRegisterFeedback() {
- return $(SUBMIT_FEEDBACK_ID).length > 0;
+ return $(SUBMIT_FEEDBACK_ID).length > 0;
}
function registerToasts() {
- const toastElements = document.querySelectorAll('.toast');
- const toastList = [...toastElements].map(toast => {
- new bootstrap.Toast(toast, TOAST_OPTIONS);
- });
+ const toastElements = document.querySelectorAll(".toast");
+ [...toastElements].map((toast) => {
+ new bootstrap.Toast(toast, TOAST_OPTIONS);
+ });
}
function registerSubmitButtonHandler() {
- const submitButton = $('#submit-feedback-form-btn');
-
- // Invoke the hidden submit button inside the actual Rails form
- $('#submit-feedback-form-btn-outside').click(() => {
- submitButton.click();
- });
-
- // Submit form by pressing Ctrl + Enter
- document.addEventListener('keydown', (event) => {
- const isModalOpen = $(SUBMIT_FEEDBACK_ID).is(':visible');
- if (isModalOpen && event.ctrlKey && event.key == "Enter") {
- submitButton.click();
- }
- });
+ const submitButton = $("#submit-feedback-form-btn");
+
+ // Invoke the hidden submit button inside the actual Rails form
+ $("#submit-feedback-form-btn-outside").click(() => {
+ submitButton.click();
+ });
+
+ // Submit form by pressing Ctrl + Enter
+ document.addEventListener("keydown", (event) => {
+ const isModalOpen = $(SUBMIT_FEEDBACK_ID).is(":visible");
+ if (isModalOpen && event.ctrlKey && event.key == "Enter") {
+ submitButton.click();
+ }
+ });
}
function registerFeedbackBodyValidator() {
- const feedbackBody = document.getElementById('feedback_feedback');
- feedbackBody.addEventListener('input', () => {
- if (feedbackBody.validity.tooShort) {
- const tooShortMessage = feedbackBody.dataset.tooShortMessage;
- feedbackBody.setCustomValidity(tooShortMessage);
- } else {
- // render input valid, so that form will submit
- feedbackBody.setCustomValidity('');
- }
- });
+ const feedbackBody = document.getElementById("feedback_feedback");
+ feedbackBody.addEventListener("input", () => {
+ if (feedbackBody.validity.tooShort) {
+ const tooShortMessage = feedbackBody.dataset.tooShortMessage;
+ feedbackBody.setCustomValidity(tooShortMessage);
+ }
+ else {
+ // render input valid, so that form will submit
+ feedbackBody.setCustomValidity("");
+ }
+ });
}
From aaf9d37ef2e2e46a3bcfde3e9afa1b7e7b4c4109 Mon Sep 17 00:00:00 2001
From: Splines
Date: Thu, 25 Jan 2024 20:09:46 +0100
Subject: [PATCH 50/57] Fix RuboCop errors
---
app/mailers/feedback_mailer.rb | 4 ++--
db/migrate/20230529080510_create_feedbacks.rb | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/app/mailers/feedback_mailer.rb b/app/mailers/feedback_mailer.rb
index 9355cfe12..152b1378b 100644
--- a/app/mailers/feedback_mailer.rb
+++ b/app/mailers/feedback_mailer.rb
@@ -5,11 +5,11 @@ class FeedbackMailer < ApplicationMailer
# Mail to the MaMpf developers including the new feedback of a user.
def new_user_feedback_email
@feedback = params[:feedback]
- reply_to_mail = @feedback.can_contact ? @feedback.user.email : ''
+ reply_to_mail = @feedback.can_contact ? @feedback.user.email : ""
subject = "Feedback: #{@feedback.title}"
mail(to: DefaultSetting::FEEDBACK_EMAIL,
subject: subject,
- content_type: 'text/plain',
+ content_type: "text/plain",
reply_to: reply_to_mail)
end
end
diff --git a/db/migrate/20230529080510_create_feedbacks.rb b/db/migrate/20230529080510_create_feedbacks.rb
index 177ff9311..a36effc6d 100644
--- a/db/migrate/20230529080510_create_feedbacks.rb
+++ b/db/migrate/20230529080510_create_feedbacks.rb
@@ -3,7 +3,7 @@ def change
create_table :feedbacks do |t|
t.text :title
t.text :feedback
- t.boolean :can_contact, default: false
+ t.boolean :can_contact, default: false, null: false
t.references :user, null: false, foreign_key: true
t.timestamps
From db8173e4227c15b085dcef6f8a394c2daa03e5da Mon Sep 17 00:00:00 2001
From: Splines
Date: Thu, 25 Jan 2024 20:10:26 +0100
Subject: [PATCH 51/57] Fix remaining ESLint errors
---
app/views/feedbacks/create.js.erb | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/app/views/feedbacks/create.js.erb b/app/views/feedbacks/create.js.erb
index 69b7e5747..1538b24bf 100644
--- a/app/views/feedbacks/create.js.erb
+++ b/app/views/feedbacks/create.js.erb
@@ -1,7 +1,7 @@
<% if @feedback_success %>
- $('#submit-feedback').modal('hide');
- $('#submit-feedback').find('form').trigger('reset'); // clear form
- $('#toast-successfully-sent').toast('show');
+$("#submit-feedback").modal("hide");
+$("#submit-feedback").find("form").trigger("reset"); // clear form
+$("#toast-successfully-sent").toast("show");
<% else %>
- $('#toast-could-not-send').toast('show');
+$("#toast-could-not-send").toast("show");
<% end %>
From be140b5b24b6dbddb528f8d9da13a2d35d3c38eb Mon Sep 17 00:00:00 2001
From: Splines
Date: Thu, 25 Jan 2024 20:32:40 +0100
Subject: [PATCH 52/57] Update timestamp of feedback migration
---
...eate_feedbacks.rb => 20240125180000_create_feedbacks.rb} | 0
db/schema.rb | 6 +++---
2 files changed, 3 insertions(+), 3 deletions(-)
rename db/migrate/{20230529080510_create_feedbacks.rb => 20240125180000_create_feedbacks.rb} (100%)
diff --git a/db/migrate/20230529080510_create_feedbacks.rb b/db/migrate/20240125180000_create_feedbacks.rb
similarity index 100%
rename from db/migrate/20230529080510_create_feedbacks.rb
rename to db/migrate/20240125180000_create_feedbacks.rb
diff --git a/db/schema.rb b/db/schema.rb
index 0f5168ee6..893ebcec9 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema[7.0].define(version: 2024_01_16_180000) do
+ActiveRecord::Schema[7.0].define(version: 2024_01_25_180000) do
# These are extensions that must be enabled in order to support this database
enable_extension "pgcrypto"
enable_extension "plpgsql"
@@ -192,7 +192,7 @@
create_table "feedbacks", force: :cascade do |t|
t.text "title"
t.text "feedback"
- t.boolean "can_contact", default: false
+ t.boolean "can_contact", default: false, null: false
t.bigint "user_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
@@ -921,7 +921,7 @@
add_foreign_key "commontator_subscriptions", "commontator_threads", column: "thread_id", on_update: :cascade, on_delete: :cascade
add_foreign_key "course_self_joins", "courses"
add_foreign_key "divisions", "programs"
- add_foreign_key "feedbacks", "users", on_delete: :cascade
+ add_foreign_key "feedbacks", "users"
add_foreign_key "imports", "media"
add_foreign_key "items", "media"
add_foreign_key "items", "sections"
From 5374cb27918bafe92dae3445a7f0e3f3807182bd Mon Sep 17 00:00:00 2001
From: Splines
Date: Thu, 25 Jan 2024 20:46:54 +0100
Subject: [PATCH 53/57] Add missing Feedback email to prod docker.env
---
docker/production/docker.env | 1 +
1 file changed, 1 insertion(+)
diff --git a/docker/production/docker.env b/docker/production/docker.env
index d5dc660b8..b9588f0eb 100644
--- a/docker/production/docker.env
+++ b/docker/production/docker.env
@@ -20,6 +20,7 @@ IMAPSERVER=mail.mathi.uni-heidelberg.de
PROJECT_EMAIL_USERNAME=creativeusername
PROJECT_EMAIL_PASSWORD=secretsecret
PROJECT_EMAIL_MAILBOX=Other Users/mampf
+FEEDBACK_EMAIL=mampf-feedback-mail
FEEDBACK_EMAIL_USERNAME=creative-feedback-username
FEEDBACK_EMAIL_PASSWORD=creative-feedback-password
From da0b409b882e7ee72fa7517f1365d1d12775e144 Mon Sep 17 00:00:00 2001
From: Splines
Date: Tue, 19 Mar 2024 12:31:22 +0100
Subject: [PATCH 54/57] Remove unnecessary Feedback env variables
---
docker/development/docker-compose.yml | 2 --
docker/production/docker.env | 2 --
2 files changed, 4 deletions(-)
diff --git a/docker/development/docker-compose.yml b/docker/development/docker-compose.yml
index e462a17f9..212d2fd6f 100644
--- a/docker/development/docker-compose.yml
+++ b/docker/development/docker-compose.yml
@@ -113,8 +113,6 @@ services:
PROJECT_EMAIL_USERNAME: mampf
PROJECT_EMAIL_PASSWORD: mampf
PROJECT_EMAIL_MAILBOX: INBOX
- FEEDBACK_EMAIL_USERNAME: mampf
- FEEDBACK_EMAIL_PASSWORD: mampf
BLOG: https://mampf.blog
# uncomment DB_SQL_PRESEED_URL and UPLOADS_PRESEED_URL to enable db preseeding
# DB_SQL_PRESEED_URL: "https://heibox.uni-heidelberg.de/d/6fb4a9d2e7f54d8b9931/files/?p=%2F20220923120841_mampf.sql&dl=1"
diff --git a/docker/production/docker.env b/docker/production/docker.env
index a214c5523..886040d36 100644
--- a/docker/production/docker.env
+++ b/docker/production/docker.env
@@ -25,8 +25,6 @@ PROJECT_EMAIL_MAILBOX="Other Users/mampf"
MAMPF_EMAIL_USERNAME=secret
MAMPF_EMAIL_PASSWORD=secret
FEEDBACK_EMAIL=mampf-feedback-mail
-FEEDBACK_EMAIL_USERNAME=secret
-FEEDBACK_EMAIL_PASSWORD=secret
# Due to CORS constraints, some urls are proxied to the media server
DOWNLOAD_LOCATION=https://mampf.mathi.uni-heidelberg.de/mediaforward
From ebf95cb2e5741091a910e210385a95427c15acfe Mon Sep 17 00:00:00 2001
From: Splines
Date: Tue, 19 Mar 2024 18:14:05 +0100
Subject: [PATCH 55/57] Add validation message for empty body
---
app/assets/javascripts/feedback.js | 40 ++++++++++++++-------
app/views/feedbacks/_feedback_form.html.erb | 3 +-
config/locales/de.yml | 2 ++
config/locales/en.yml | 2 ++
4 files changed, 34 insertions(+), 13 deletions(-)
diff --git a/app/assets/javascripts/feedback.js b/app/assets/javascripts/feedback.js
index 57d243602..4cf7ab8f0 100644
--- a/app/assets/javascripts/feedback.js
+++ b/app/assets/javascripts/feedback.js
@@ -27,18 +27,16 @@ function registerToasts() {
}
function registerSubmitButtonHandler() {
- const submitButton = $("#submit-feedback-form-btn");
-
// Invoke the hidden submit button inside the actual Rails form
$("#submit-feedback-form-btn-outside").click(() => {
- submitButton.click();
+ submitFeedback();
});
// Submit form by pressing Ctrl + Enter
document.addEventListener("keydown", (event) => {
const isModalOpen = $(SUBMIT_FEEDBACK_ID).is(":visible");
if (isModalOpen && event.ctrlKey && event.key == "Enter") {
- submitButton.click();
+ submitFeedback();
}
});
}
@@ -46,13 +44,31 @@ function registerSubmitButtonHandler() {
function registerFeedbackBodyValidator() {
const feedbackBody = document.getElementById("feedback_feedback");
feedbackBody.addEventListener("input", () => {
- if (feedbackBody.validity.tooShort) {
- const tooShortMessage = feedbackBody.dataset.tooShortMessage;
- feedbackBody.setCustomValidity(tooShortMessage);
- }
- else {
- // render input valid, so that form will submit
- feedbackBody.setCustomValidity("");
- }
+ validateFeedback();
});
}
+
+function validateFeedback() {
+ const feedbackBody = document.getElementById("feedback_feedback");
+ const validityState = feedbackBody.validity;
+ if (validityState.tooShort) {
+ const tooShortMessage = feedbackBody.dataset.tooShortMessage;
+ feedbackBody.setCustomValidity(tooShortMessage);
+ }
+ else if (validityState.valueMissing) {
+ const valueMissingMessage = feedbackBody.dataset.valueMissingMessage;
+ feedbackBody.setCustomValidity(valueMissingMessage);
+ }
+ else {
+ // render input valid, so that form will submit
+ feedbackBody.setCustomValidity("");
+ }
+
+ feedbackBody.reportValidity();
+}
+
+function submitFeedback() {
+ const submitButton = $("#submit-feedback-form-btn");
+ validateFeedback();
+ submitButton.click();
+}
diff --git a/app/views/feedbacks/_feedback_form.html.erb b/app/views/feedbacks/_feedback_form.html.erb
index 18694dbe4..2e0833e3e 100644
--- a/app/views/feedbacks/_feedback_form.html.erb
+++ b/app/views/feedbacks/_feedback_form.html.erb
@@ -29,7 +29,8 @@
minlength: Feedback::BODY_MIN_LENGTH,
maxlength: Feedback::BODY_MAX_LENGTH,
'data-too-short-message': t('feedback.body_too_short_error',
- min_length: Feedback::BODY_MIN_LENGTH) %>
+ min_length: Feedback::BODY_MIN_LENGTH),
+ 'data-value-missing-message': t('feedback.body_missing_error') %>
<%= f.label :feedback, t('feedback.comment') %>
diff --git a/config/locales/de.yml b/config/locales/de.yml
index d5d8d2632..13ae67031 100644
--- a/config/locales/de.yml
+++ b/config/locales/de.yml
@@ -3813,6 +3813,8 @@ de:
gerne auch über dieses Formular oder direkt per %{feedback_mail}.
body_too_short_error: >
Dein Feedback ist zu kurz. Bitte gib mindestens %{min_length} Zeichen ein.
+ body_missing_error: >
+ Bitte gib hier Dein Feedback ein.
mail_checkbox: >
Erlaube es uns, Dich per E-Mail (%{user_mail}) zu kontaktieren, falls es
Rückfragen zu Deinem Feedback gibt.
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 50b428b19..0f738f912 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -3606,6 +3606,8 @@ en:
form or send an %{feedback_mail} directly.
body_too_short_error: >
Your feedback is too short. Please enter at least %{min_length} characters.
+ body_missing_error: >
+ Please enter your feedback here.
mail_checkbox: >
Allow us to contact you via email (%{user_mail}) if there are questions
about your feedback.
From d5c2e0ce2d04fd6b2920329ea12dac0c6f981eeb Mon Sep 17 00:00:00 2001
From: Splines
Date: Tue, 19 Mar 2024 18:14:52 +0100
Subject: [PATCH 56/57] Change `const` to `var` to avoid "redefined" errors
---
app/assets/javascripts/feedback.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/app/assets/javascripts/feedback.js b/app/assets/javascripts/feedback.js
index 4cf7ab8f0..7d9ab3772 100644
--- a/app/assets/javascripts/feedback.js
+++ b/app/assets/javascripts/feedback.js
@@ -7,9 +7,9 @@ $(document).on("turbolinks:load", () => {
registerFeedbackBodyValidator();
});
-const SUBMIT_FEEDBACK_ID = "#submit-feedback";
+var SUBMIT_FEEDBACK_ID = "#submit-feedback";
-const TOAST_OPTIONS = {
+var TOAST_OPTIONS = {
animation: true,
autohide: true,
delay: 6000, // autohide after ... milliseconds
From a36cf52292ea4a14471266c53c45a99ff3b155fb Mon Sep 17 00:00:00 2001
From: Splines
Date: Tue, 19 Mar 2024 18:16:13 +0100
Subject: [PATCH 57/57] Update timestamp of feedback migration (again)
---
...0_create_feedbacks.rb => 20240319130000_create_feedbacks.rb} | 0
db/schema.rb | 2 +-
2 files changed, 1 insertion(+), 1 deletion(-)
rename db/migrate/{20240125180000_create_feedbacks.rb => 20240319130000_create_feedbacks.rb} (100%)
diff --git a/db/migrate/20240125180000_create_feedbacks.rb b/db/migrate/20240319130000_create_feedbacks.rb
similarity index 100%
rename from db/migrate/20240125180000_create_feedbacks.rb
rename to db/migrate/20240319130000_create_feedbacks.rb
diff --git a/db/schema.rb b/db/schema.rb
index 423121de5..d17bf4c82 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema[7.0].define(version: 2024_02_15_100000) do
+ActiveRecord::Schema[7.0].define(version: 2024_03_19_130000) do
# These are extensions that must be enabled in order to support this database
enable_extension "pgcrypto"
enable_extension "plpgsql"