Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 20 additions & 8 deletions app/assets/javascripts/admin/commons/conditional.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,31 @@ window.osuny.conditional = {
update: function (source, value) {
'use strict';
var allTargets = document.querySelectorAll('[data-conditional-source="' + source + '"]'),
activeTargets = document.querySelectorAll('[data-conditional-source="' + source + '"][data-conditional-value="' + value + '"]'),
i,
target;
for (i = 0; i < allTargets.length; i += 1) {
target = allTargets[i];
this.hide(target);
if (this.matches(target, value)) {
this.show(target);
} else {
this.hide(target);
}
}
for (i = 0; i < activeTargets.length; i += 1) {
target = activeTargets[i];
this.show(target);
},

// data-conditional-value="x": displayed only when value equals to x
// data-conditional-value-not="x": displayed when value different from x
matches: function (target, value) {
'use strict';
if (target.hasAttribute('data-conditional-value-not')) {
return target.getAttribute('data-conditional-value-not') !== value;
}
return target.getAttribute('data-conditional-value') === value;
},

hide: function (target) {
'use strict';
var input = target.querySelector('select');
var input = target.querySelector('select, input, textarea');
target.classList.add('d-none');
if (input) {
input.removeAttribute('required');
Expand All @@ -45,11 +54,14 @@ window.osuny.conditional = {

show: function (target) {
'use strict';
var input = target.querySelector('select');
var input = target.querySelector('select, input, textarea'),
optional = target.getAttribute('data-conditional-optional') === 'true';
target.classList.remove('d-none');
if (input) {
input.removeAttribute('disabled');
input.setAttribute('required', 'required');
if (!optional) {
input.setAttribute('required', 'required');
}
}
},

Expand Down
51 changes: 51 additions & 0 deletions app/assets/javascripts/admin/commons/dynamic_placeholder.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/* global */
window.osuny.dynamicPlaceholder = {
init: function () {
'use strict';
var element,
i;
this.elements = document.querySelectorAll('[data-placeholder-source]');
for (i = 0; i < this.elements.length; i += 1) {
element = this.elements[i];
this.bind(element);
}
},

bind: function (element) {
'use strict';
var source = document.getElementById(element.getAttribute('data-placeholder-source'));
if (!source) {
return;
}
source.addEventListener('change', this.update.bind(this, element, source));
this.update(element, source);
},

// data-placeholder-map='{"value-from-source": "placeholder to display", ...}'
update: function (element, source) {
'use strict';
var map = JSON.parse(element.getAttribute('data-placeholder-map') || '{}'),
value = map[this.getValue(source)];
if (value) {
element.setAttribute('placeholder', value);
} else {
element.removeAttribute('placeholder');
}
},

getValue: function (element) {
'use strict';
if (element.type === 'checkbox') {
return element.checked;
} else {
return element.value;
}
},

invoke: function () {
'use strict';
return {
init: this.init.bind(this)
};
}
}.invoke().init();
36 changes: 36 additions & 0 deletions app/assets/javascripts/admin/commons/hide_on_change.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/* global */
window.osuny.hideOnChange = {
init: function () {
'use strict';
var element,
i;
this.elements = document.querySelectorAll('[data-hide-on-change]');
for (i = 0; i < this.elements.length; i += 1) {
element = this.elements[i];
this.bind(element);
}
},

bind: function (element) {
'use strict';
var container = document.getElementById(element.getAttribute('data-hide-on-change'));
if (!container) {
return;
}
container.addEventListener('input', this.hide.bind(this, element));
container.addEventListener('change', this.hide.bind(this, element));
},

// If any field in the container has changed, hide the element
hide: function (element) {
'use strict';
element.classList.add('d-none');
},

invoke: function () {
'use strict';
return {
init: this.init.bind(this)
};
}
}.invoke().init();
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,19 @@ def redirects
def technical
breadcrumb
add_breadcrumb t('admin.communication.website.technical.label')
check_git_access if params[:check_git_access].present?
end

protected

def check_git_access
if @website.check_git_access
flash.now[:notice] = t('admin.communication.website.technical.check_git_access.success')
else
flash.now[:alert] = @website.errors.full_messages.to_sentence
end
end

def breadcrumb
super
add_breadcrumb t('admin.subnav.settings'), edit_admin_communication_website_path(@website, website_id: nil)
Expand Down
14 changes: 12 additions & 2 deletions app/controllers/admin/communication/websites_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ def show
can?(:read, Communication::Website::Jobboard::Job)
# Git files
@desynchronized_generated_git_files = @website.desynchronized_generated_git_files
@sync_with_git_scheduled = @website.sync_with_git_scheduled?
breadcrumb
end

Expand Down Expand Up @@ -103,8 +104,17 @@ def update
else
load_invalid_localization
breadcrumb
add_breadcrumb t('edit')
render :edit, status: :unprocessable_content
case params[:_return_to]
when 'technical'
@l10n = @website.localization_for(current_language)
@feature_nav = 'navigation/admin/communication/website/settings'
add_breadcrumb t('admin.subnav.settings'), edit_admin_communication_website_path(@website, website_id: nil)
add_breadcrumb t('admin.communication.website.technical.label')
render 'admin/communication/websites/settings/technical', status: :unprocessable_content
else
add_breadcrumb t('edit')
render :edit, status: :unprocessable_content
end
end
end

Expand Down
6 changes: 6 additions & 0 deletions app/controllers/server/websites_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ def analyse
notice: t('admin.communication.website.git_file.analysis.launched')
end

def force_resync_with_git
@website.force_resync_with_git!
redirect_back fallback_location: server_website_path(@website),
notice: t('server_admin.websites.force_resync_with_git_notice')
end

def edit
breadcrumb
add_breadcrumb t('edit')
Expand Down
42 changes: 40 additions & 2 deletions app/jobs/communication/website/base_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,38 @@ class Communication::Website::BaseJob < ApplicationJob

queue_as :elephants

discard_on ActiveJob::DeserializationError, # Discard if object does not exist anymore
Octokit::InvalidRepository # Discard if repository is invalid to prevent useless API calls
# Discard if object does not exist anymore
discard_on ActiveJob::DeserializationError

# For any error not handled by our custom error classes in discard_on,
# requests that return error are retried 5 times with exponential backoff
# if it does not self-heal, notify admins with raw api error message.
retry_on Git::Providers::Abstract::Error, wait: :polynomially_longer, attempts: 5 do |job, error|
job.notify_git_access_broken(error)
end

# A client side error would not self-heal, notify admins.
discard_on Git::Providers::Abstract::ClientError do |job, error|
job.notify_git_access_broken(error)
end

# Discard immediately and notify admins
# (a wrong or expired token does not come back on its own).
discard_on Git::Providers::Abstract::Unauthorized do |job, error|
job.notify_invalid_access_token
end

# Discard if the remote git access has drifted since it was last validated
# (repository/branch deleted, branch newly protected, endpoint reconfigured...).
# Unlike a generic network error, nothing self-heals this on the next run: notify admins.
discard_on Git::Providers::Abstract::RepositoryForbidden,
Git::Providers::Abstract::RepositoryNotFound,
Git::Providers::Abstract::BranchNotFound,
Git::Providers::Abstract::BranchProtected,
Git::Providers::Abstract::InvalidEndpoint,
Git::Providers::Abstract::WorkflowsForbidden do |job, error|
job.notify_git_access_broken(error)
end

# Retry the job after 1 minute if it is interrupted, to prevent queue from being blocked
retry_on GoodJob::InterruptError, wait: 1.minute, attempts: Float::INFINITY
Expand All @@ -33,6 +63,14 @@ def perform(website_id, options = {})
end
end

def notify_git_access_broken(error)
website&.notify_git_access_broken!(error)
end

def notify_invalid_access_token
website&.notify_invalid_access_token!
end

protected

def execute
Expand Down
24 changes: 23 additions & 1 deletion app/mailers/notification_mailer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,32 @@ def emergency_message(emergency_message, user, lang)
end
end

def website_git_access_broken(website, user, error_message)
@website = website
@error_message = error_message
merge_with_university_infos(@website.university, {})
# Link with check_git_access: true to trigger automatically the check
@url = technical_admin_communication_website_url(
id: @website.id, check_git_access: true,
lang: @website.default_language.iso_code
)
I18n.with_locale(user.language.iso_code) do
subject = t('mailers.notifications.website_git_access_broken.subject', website: website)
mail(
from: user.university.mail_from[:full],
to: user.email,
subject: subject
) if should_send?(user.email)
end
end

def website_invalid_access_token(website, user)
@website = website
merge_with_university_infos(@website.university, {})
@url = edit_admin_communication_website_url(@website, lang: @website.default_language.iso_code)
@url = technical_admin_communication_website_url(
id: @website.id,
lang: @website.default_language.iso_code
)
I18n.with_locale(user.language.iso_code) do
subject = t('mailers.notifications.website_invalid_access_token.subject', website: website)
mail(
Expand Down
3 changes: 2 additions & 1 deletion app/models/communication/website.rb
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ class Communication::Website < ApplicationRecord

enum :git_provider, {
github: 0,
gitlab: 1
gitlab: 1,
forgejo: 2
}

belongs_to :default_language, class_name: "Language"
Expand Down
Loading
Loading