From 60a9b269fbeb94c4e714a5b1ce30b9efdaf1f9a5 Mon Sep 17 00:00:00 2001 From: Gabina Luz Bianchi Date: Mon, 13 Jan 2025 23:03:27 -0300 Subject: [PATCH 01/25] Revert "Adheres to `prefer-promise-reject-errors` eslint rule" This reverts commit 1b1e210295f4efba58b96f96bdb46a71b82ce2bc. --- app/assets/javascripts/actions/uploads_actions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/actions/uploads_actions.js b/app/assets/javascripts/actions/uploads_actions.js index c0cf2c306a..0a9b1bc274 100644 --- a/app/assets/javascripts/actions/uploads_actions.js +++ b/app/assets/javascripts/actions/uploads_actions.js @@ -10,7 +10,7 @@ const fetchUploads = (courseId) => { if (res.ok && res.status === 200) { return res.json(); } - return Promise.reject(new Error(`Failed to fetch uploads. Status: ${res.status}`)); + return Promise.reject({ error: 'Failed to fetch uploads', status: res.status }); }) .catch((error) => { logErrorMessage(error); From 926d7d141eab9f06a36663553f5199c80c89e49e Mon Sep 17 00:00:00 2001 From: Gabina Luz Bianchi Date: Mon, 13 Jan 2025 23:03:27 -0300 Subject: [PATCH 02/25] Revert "Fixes `uploads.json` endpoint returns `500 internal server error` for some courses: - Uses `CGI.unescape` to decode url encoded string to their original formats if applicable thus solving cause of 500 error - Improves error handling in js actions and reducers to not result in TypeErrors when a 500 error (or any other error) occurs" This reverts commit aec776a345cb4050b6069f727dc3f00588ce447b. --- .../javascripts/actions/uploads_actions.js | 27 +++++++------------ app/assets/javascripts/reducers/uploads.js | 2 +- app/helpers/uploads_helper.rb | 2 +- spec/helpers/uploads_helper_spec.rb | 9 ------- 4 files changed, 11 insertions(+), 29 deletions(-) diff --git a/app/assets/javascripts/actions/uploads_actions.js b/app/assets/javascripts/actions/uploads_actions.js index 0a9b1bc274..a15da975c5 100644 --- a/app/assets/javascripts/actions/uploads_actions.js +++ b/app/assets/javascripts/actions/uploads_actions.js @@ -10,34 +10,25 @@ const fetchUploads = (courseId) => { if (res.ok && res.status === 200) { return res.json(); } - return Promise.reject({ error: 'Failed to fetch uploads', status: res.status }); + return Promise.reject(res); }) .catch((error) => { logErrorMessage(error); - return { error: 'Failed to fetch uploads', status: error.status || 500 }; }); }; export const receiveUploads = courseId => (dispatch) => { - return fetchUploads(courseId) - .then((resp) => { - if (!resp) { - return dispatch({ - type: API_FAIL, - data: { error: 'No response received' }, - }); - } - return dispatch({ + return ( + fetchUploads(courseId) + .then(resp => dispatch({ type: RECEIVE_UPLOADS, data: resp, - }); - }) - .catch((resp) => { - dispatch({ + })) + .catch(resp => dispatch({ type: API_FAIL, - data: resp, - }); - }); + data: resp + })) + ); }; const fetchUploadMetadata = (uploads) => { diff --git a/app/assets/javascripts/reducers/uploads.js b/app/assets/javascripts/reducers/uploads.js index f5c256969e..69e90ed293 100644 --- a/app/assets/javascripts/reducers/uploads.js +++ b/app/assets/javascripts/reducers/uploads.js @@ -30,7 +30,7 @@ const SORT_DESCENDING = { export default function uploads(state = initialState, action) { switch (action.type) { case RECEIVE_UPLOADS: { - const dataUploads = action.data?.course?.uploads || []; + const dataUploads = action.data.course.uploads; // Intial sorting by upload date const sortedModel = sortByKey(dataUploads, 'uploaded_at', state.sortKey, SORT_DESCENDING.uploaded_at); diff --git a/app/helpers/uploads_helper.rb b/app/helpers/uploads_helper.rb index 9e4fc8c8e4..281081c876 100644 --- a/app/helpers/uploads_helper.rb +++ b/app/helpers/uploads_helper.rb @@ -3,7 +3,7 @@ #= Helpers for course views module UploadsHelper def pretty_filename(upload) - pretty = CGI.unescape(upload.file_name) + pretty = upload.file_name pretty['File:'] = '' pretty end diff --git a/spec/helpers/uploads_helper_spec.rb b/spec/helpers/uploads_helper_spec.rb index d03f4c2c99..91ae000087 100644 --- a/spec/helpers/uploads_helper_spec.rb +++ b/spec/helpers/uploads_helper_spec.rb @@ -10,14 +10,5 @@ result = pretty_filename(upload) expect(result).to eq('My file.jpg') end - - it 'formats a complex filename with encoded characters nicely for display' do - upload = build(:commons_upload, - # rubocop:disable Layout/LineLength - file_name: 'File%3AA+sunflower+%F0%9F%8C%BB%F0%9F%8C%BB+in+Kaduna+Polytechnic%2CSabo+Campus.jpg') - # rubocop:enable Layout/LineLength - result = pretty_filename(upload) - expect(result).to eq('A sunflower 🌻🌻 in Kaduna Polytechnic,Sabo Campus.jpg') - end end end From 587a3cc8d5aae84e1991675f0f975a1d630c6bf7 Mon Sep 17 00:00:00 2001 From: Gabina Luz Bianchi Date: Mon, 13 Jan 2025 23:03:27 -0300 Subject: [PATCH 03/25] Revert "Chore: Rename `enableMutationChecks` to `enableReduxSafetyChecks`" This reverts commit 9e8db24473c261aaca4efa9c20b5d60556a3a3f6. --- app/assets/javascripts/components/util/create_store.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/assets/javascripts/components/util/create_store.js b/app/assets/javascripts/components/util/create_store.js index 95a5fbb3a2..98bbd57184 100644 --- a/app/assets/javascripts/components/util/create_store.js +++ b/app/assets/javascripts/components/util/create_store.js @@ -29,8 +29,8 @@ export const getStore = () => { }; } - // Determine if Redux Toolkit's safety checks should be enabled - const enableReduxSafetyChecks = false; + // Determine if mutation checks should be enabled + const enableMutationChecks = false; const store = configureStore({ reducer, @@ -39,9 +39,9 @@ export const getStore = () => { getDefaultMiddleware({ // Temporarily disable mutation checks feature to facilitate Redux Toolkit migration. // TODO: Gradually resolve state mutations and re-enable these checks in the future. - // Enable mutation checks when resolving or detecting these issues by setting enableReduxSafetyChecks to true. - immutableCheck: enableReduxSafetyChecks, - serializableCheck: enableReduxSafetyChecks, + // Enable mutation checks when resolving or detecting these issues by setting enableMutationChecks to true. + immutableCheck: enableMutationChecks, + serializableCheck: enableMutationChecks, }), }); From 35c21943cc6bbd31863002563e09049bf0dedb1b Mon Sep 17 00:00:00 2001 From: Gabina Luz Bianchi Date: Mon, 13 Jan 2025 23:03:27 -0300 Subject: [PATCH 04/25] Revert "Fix: Prevent state mutation in fetchRevisionsPromise function" This reverts commit 0db93531a2c6208e20e18df50537bbd9ecf41fd0. --- .../javascripts/actions/revisions_actions.js | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/app/assets/javascripts/actions/revisions_actions.js b/app/assets/javascripts/actions/revisions_actions.js index 918c1bf3ab..7cc9d4af07 100644 --- a/app/assets/javascripts/actions/revisions_actions.js +++ b/app/assets/javascripts/actions/revisions_actions.js @@ -1,3 +1,4 @@ + import { RECEIVE_REVISIONS, REVISIONS_LOADING, @@ -34,19 +35,12 @@ const fetchAllArticles = async (course) => { const fetchRevisionsPromise = async (course, users, last_date, dispatch) => { const { revisions, last_date: new_last_date } = await fetchRevisionsFromUsers(course, users, 7, last_date); + course.revisions = sortRevisionsByDate(revisions); - // Create a new course object with updated revisions - const updatedCourse = { - ...course, - revisions: sortRevisionsByDate(revisions), - }; - - // we don't await this. When the assessments/references get loaded, the action is dispatched + // we don't await this. When the assessments/references get laoded, the action is dispatched fetchRevisionsAndReferences(revisions, dispatch); - - return { course: updatedCourse, last_date: new_last_date }; + return { course, last_date: new_last_date }; }; - const fetchRevisionsCourseSpecificPromise = async (course, users, last_date, dispatch, articles) => { const trackedArticles = new Set( articles.filter(article => article.tracked).map(article => article.title) From 6e0cbe0c9f5365c34a0393a517468b1754c46d2b Mon Sep 17 00:00:00 2001 From: Gabina Luz Bianchi Date: Mon, 13 Jan 2025 23:03:27 -0300 Subject: [PATCH 05/25] Revert "Localisation updates from https://translatewiki.net." This reverts commit e980866e4bcd61132b0fb6daae82662f9b3a3c6b. --- config/locales/fr.yml | 2 +- config/locales/lb.yml | 2 +- config/locales/se.yml | 1 - config/locales/smn.yml | 1 - config/locales/sms.yml | 1 - 5 files changed, 2 insertions(+), 5 deletions(-) diff --git a/config/locales/fr.yml b/config/locales/fr.yml index ace62afa0f..b4a893c305 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -1790,7 +1790,7 @@ fr: user_training_status: État de la formation user_no_training_status: Cet utilisateur n’a terminé aucun des modules de formation. up_to_date_with_training: formation à jour - uploads_doc: Nombre de fichiers téléversés sur Wikimedia Commons + uploads_doc: Nombre de fichiers téléversés sur Wikimédia Commons ungreeted: Pas le bienvenu username: Nom d’utilisateur username_placeholder: Nom d’utilisateur diff --git a/config/locales/lb.yml b/config/locales/lb.yml index b4a3e0da28..5e78823525 100644 --- a/config/locales/lb.yml +++ b/config/locales/lb.yml @@ -462,7 +462,7 @@ lb: next_update: Nächst erwaart Aktualiséierung activity: Rezent Aktivitéit articles_edited: Geännert Artikelen - bytes_added: Byte derbäigesat + bytes_added: Byten derbäigesat characters: Buschtawen char_changed: Geännert Buschtawen close_modal: Zoumaachen diff --git a/config/locales/se.yml b/config/locales/se.yml index 603720a472..7cd94eced9 100644 --- a/config/locales/se.yml +++ b/config/locales/se.yml @@ -62,7 +62,6 @@ se: loading: Viežžamin bargguid... remove: Sihko select: Vállje - submit: Sádde campaign: alert_label: Kampánjja várrehusat alert_user_id: Geavaheaddji diff --git a/config/locales/smn.yml b/config/locales/smn.yml index 302e410736..3256dec21d 100644 --- a/config/locales/smn.yml +++ b/config/locales/smn.yml @@ -64,7 +64,6 @@ smn: article_link: Artikkâl add_available_submit: Lasseet artikkâlijd remove: Siho - submit: Vuolgât campaign: alert_user_id: Kevttee description: Kuvvim diff --git a/config/locales/sms.yml b/config/locales/sms.yml index aa6984052d..0a559030c5 100644 --- a/config/locales/sms.yml +++ b/config/locales/sms.yml @@ -58,7 +58,6 @@ sms: confirm_add_available: Haaʹlääk-a ton tuõđi artikkeeʹl %{title} lââʹzzted? remove: Jaukkâd select: Vaʹlljed - submit: Vuõlttâd campaign: alert_article: Artikkeeʹl nõmm alert_user_id: Õõʹnni From a4f2093720c842a01a7eeda6af91e8e7a3cfc20e Mon Sep 17 00:00:00 2001 From: Gabina Luz Bianchi Date: Mon, 13 Jan 2025 23:03:27 -0300 Subject: [PATCH 06/25] Revert "Remove debugging line" This reverts commit 9853a34443fd38bbb4b5c74c099340819714f755. --- lib/petscan_api.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/petscan_api.rb b/lib/petscan_api.rb index cfe680e562..3dcddfb12d 100644 --- a/lib/petscan_api.rb +++ b/lib/petscan_api.rb @@ -8,6 +8,7 @@ class PetScanApi def get_data(psid, update_service: nil) url = query_url(psid) response = petscan.get url + puts response.body Oj.load(response.body) rescue StandardError => e log_error(e, update_service:, From 3638657c28487c77c6e81e7f171fe2ef09af14d1 Mon Sep 17 00:00:00 2001 From: Gabina Luz Bianchi Date: Mon, 13 Jan 2025 23:03:27 -0300 Subject: [PATCH 07/25] Revert "Ensure that PagePile Category records are unique by pileid" This reverts commit a6f2b38ccdb3c7525ccc9fcbdda8bf6331aca29a. --- app/controllers/categories_controller.rb | 4 ++-- app/models/wiki_content/category.rb | 16 ---------------- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/app/controllers/categories_controller.rb b/app/controllers/categories_controller.rb index b7928298f0..b4f3b2d6e7 100644 --- a/app/controllers/categories_controller.rb +++ b/app/controllers/categories_controller.rb @@ -46,8 +46,8 @@ def update_wiki(wiki) def add_category(params) name = ArticleUtils.format_article_title(params[:name]) - @category = Category.get_or_create(wiki: @wiki, depth: params[:depth], - name:, source: params[:source]) + @category = Category.find_or_create_by(wiki: @wiki, depth: params[:depth], + name:, source: params[:source]) @course.categories << @category end end diff --git a/app/models/wiki_content/category.rb b/app/models/wiki_content/category.rb index 4ab2bfb199..638f28cd60 100644 --- a/app/models/wiki_content/category.rb +++ b/app/models/wiki_content/category.rb @@ -38,22 +38,6 @@ class Category < ApplicationRecord less_than_or_equal_to: 3 } - def self.get_or_create(wiki:, name:, depth:, source:) - if source == 'pileid' - get_or_create_by_pileid(wiki:, name:, depth:, source:) - else - find_or_create_by(wiki:, name:, depth:, source:) - end - end - - def self.get_or_create_by_pileid(wiki:, name:, depth:, source:) - # For pagepile records, the name should be unique. Depth - # is not applicable, and wiki gets set via PagePileApi if it - # doesn't match. - record = find_by(source:, name:) - return record || create(wiki:, name:, depth:, source:) - end - def self.refresh_categories_for(course, update_service: nil) # Updating categories only if they were last updated since # more than a day, or those which are newly created From d4ddbef260e89329d3e65eef7aa4d5670fde4f72 Mon Sep 17 00:00:00 2001 From: Gabina Luz Bianchi Date: Mon, 13 Jan 2025 23:03:27 -0300 Subject: [PATCH 08/25] Revert "Fix: Prevent "Preview Question Group" button from rendering empty page" This reverts commit e57ac4640ba8096767a6e4356519d1ed0964f237. --- app/views/layouts/surveys.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/layouts/surveys.html.haml b/app/views/layouts/surveys.html.haml index 4ee74b12d5..1147ec2ad1 100644 --- a/app/views/layouts/surveys.html.haml +++ b/app/views/layouts/surveys.html.haml @@ -20,6 +20,6 @@ // survey.js sometimes interferes with the rendering of results. = javascript_include_tag '/assets/javascripts/jquery.min.js' = hot_javascript_tag("survey") unless page_class == 'surveys results' - - if can_administer? && !params.key?("preview") + - if can_administer? = hot_javascript_tag("survey_admin") = content_for :additional_javascripts From a82d9feacd5f5118fadc4d86ec6301f3a32c073b Mon Sep 17 00:00:00 2001 From: Gabina Luz Bianchi Date: Mon, 13 Jan 2025 23:03:27 -0300 Subject: [PATCH 09/25] Revert "Added rapid: false parameter to textarea set method for slower driver script mode" This reverts commit 18f6367105c2ea310404f48017169dab5bce2a2f. --- spec/features/multiwiki_assignment_spec.rb | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/spec/features/multiwiki_assignment_spec.rb b/spec/features/multiwiki_assignment_spec.rb index ee1a6e99a5..118b4be516 100644 --- a/spec/features/multiwiki_assignment_spec.rb +++ b/spec/features/multiwiki_assignment_spec.rb @@ -48,6 +48,8 @@ end it 'creates valid assignments from multiple article titles' do + pending 'Fails in CI caused by Assign all button not found' + VCR.use_cassette 'multiwiki_assignment' do visit "/courses/#{course.slug}/students/articles" first('.student-selection .student').click @@ -58,8 +60,7 @@ within('#users') do first('textarea').set( - "Terre\nhttps://fr.wikipedia.org/wiki/Anglais", - rapid: false + "Terre\nhttps://fr.wikipedia.org/wiki/Anglais" ) end click_button 'Assign all' @@ -75,6 +76,8 @@ expect(page).to have_css('a[href="https://fr.wikipedia.org/wiki/Anglais"]') expect(page).to have_css('a[href="https://fr.wikipedia.org/wiki/Terre"]') end + + pass_pending_spec end it 'creates a valid assignment from an article and a project and language from tracked Wikis' do @@ -87,7 +90,7 @@ button.click within('#users') do - find('textarea', visible: true).set('No le des prisa, dolor', rapid: false) + find('textarea', visible: true).set('No le des prisa, dolor') click_link 'Change' find('div.wiki-select').click within('.wiki-select') do @@ -109,6 +112,8 @@ end it 'will create a valid assignment for multilingual wikisource projects' do + pending 'Fails in CI caused by Heyder Cansa content not found' + VCR.use_cassette 'multiwiki_assignment' do visit "/courses/#{course.slug}/students/articles" first('.student-selection .student').click @@ -117,7 +122,7 @@ expect(button).to have_content 'Assign/remove an article' button.click within('#users') do - first('textarea').set('https://wikisource.org/wiki/Heyder_Cansa', rapid: false) + first('textarea').set('https://wikisource.org/wiki/Heyder_Cansa') end click_button 'Assign' visit "/courses/#{course.slug}/students/articles" @@ -129,9 +134,13 @@ expect(link[:href]).to include('wikisource') end end + + pass_pending_spec end it 'will create a valid assignment for multilingual wikimedia incubator projects' do + pending 'Fails in CI caused by Wp/kiu/Hey content not found' + VCR.use_cassette 'multiwiki_assignment' do visit "/courses/#{course.slug}/students/articles" first('.student-selection .student').click @@ -140,8 +149,7 @@ expect(button).to have_content 'Assign/remove an article' button.click within('#users') do - first('textarea').set('https://incubator.wikimedia.org/wiki/Wp/kiu/Heyder_Cansa', - rapid: false) + first('textarea').set('https://incubator.wikimedia.org/wiki/Wp/kiu/Heyder_Cansa') end click_button 'Assign' visit "/courses/#{course.slug}/students/articles" @@ -153,5 +161,7 @@ expect(link[:href]).to include('incubator.wikimedia') end end + + pass_pending_spec end end From 847c8513e464236ef9b64711c90548c32e19787b Mon Sep 17 00:00:00 2001 From: Gabina Luz Bianchi Date: Mon, 13 Jan 2025 23:03:27 -0300 Subject: [PATCH 10/25] Revert "extended workflow to save screenshot of failed Capybara tests as artifacts for debugging" This reverts commit 90e0cfd15253c9c13cde5d08d6e46c700021e005. --- .github/workflows/ci.yml | 8 -------- spec/rails_helper.rb | 6 +----- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 95f823c302..fed3cf9e8d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -81,14 +81,6 @@ jobs: coverageCommand: bundle exec rspec spec/ --color --profile --format documentation coverageLocations: | ${{github.workspace}}/public/js_coverage/lcov.info:lcov - - - name: Archive capybara failure screenshots - uses: actions/upload-artifact@v4 - if: failure() - with: - name: dist-without-markdown - path: tmp/capybara/*.png - if-no-files-found: ignore - name: Ruby linting run: bundle exec rubocop diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 5db7a2d819..a89ea159a5 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -24,11 +24,6 @@ Rails.cache.clear Capybara::Screenshot.prune_strategy = :keep_last_run -Capybara::Screenshot.register_filename_prefix_formatter(:rspec) do |example| - file_name = example.file_path.split('/').last.gsub('.rb', '') - formatted_description = example.description.tr(' ', '-').gsub(%r{^.*/spec/}, '') - "screenshot_#{file_name}_description_#{formatted_description}" -end Capybara.save_path = 'tmp/screenshots/' Capybara.server = :puma, { Silent: true } Capybara.default_max_wait_time = 10 @@ -103,6 +98,7 @@ # them. # Instead, we clear and print any after-success error # logs in the `before` block above. + Capybara::Screenshot.screenshot_and_save_page if example.exception errors = page.driver.browser.logs.get(:browser) # pass `js_error_expected: true` to skip JS error checking From 3234a7ab390eb3c77e0f8fa7fd86b6830368a0d6 Mon Sep 17 00:00:00 2001 From: Gabina Luz Bianchi Date: Mon, 13 Jan 2025 23:03:27 -0300 Subject: [PATCH 11/25] Revert "Delete unused components" This reverts commit 544d20f423ddec5b9171a24b9786b0d388a35b12. --- .../components/activity/activity_table.jsx | 123 ++++++++++++++++++ .../activity/activity_table_row.jsx | 83 ++++++++++++ 2 files changed, 206 insertions(+) create mode 100644 app/assets/javascripts/components/activity/activity_table.jsx create mode 100644 app/assets/javascripts/components/activity/activity_table_row.jsx diff --git a/app/assets/javascripts/components/activity/activity_table.jsx b/app/assets/javascripts/components/activity/activity_table.jsx new file mode 100644 index 0000000000..f91f1e6edc --- /dev/null +++ b/app/assets/javascripts/components/activity/activity_table.jsx @@ -0,0 +1,123 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { useSelector } from 'react-redux'; +import { flatten, zip } from 'lodash-es'; +import { formatDateWithTime } from '../../utils/date_utils'; +import ActivityTableRow from './activity_table_row.jsx'; +import Loading from '../common/loading.jsx'; + +const ActivityTable = ({ onSort, activity, headers, loading, noActivityMessage }) => { + const openKey = useSelector(state => state.ui.openKey); + + const sortItems = (e) => { + onSort(e.currentTarget.getAttribute('data-sort-key')); + }; + + const _renderActivites = () => { + return activity.map((revision) => { + const roundedRevisionScore = Math.round(revision.revision_score) || 'unknown'; + const revisionDateTime = formatDateWithTime(revision.datetime); + const talkPageLink = `${revision.base_url}/wiki/User_talk:${revision.username}`; + const isOpen = openKey === `drawer_${revision.key}`; + + return ( + + ); + }); + }; + + const _renderDrawers = () => { + return activity.map((revision) => { + const courses = revision.courses.map((course) => { + return ( +
  • + {course.title} +
  • + ); + }); + + return ( + + + + + + + + + +
    + +
    {I18n.t('recent_activity.active_courses')}
    +
      + {courses} +
    +
    +
    + + + ); + }); + }; + + const _renderHeaders = () => { + return headers.map((header) => { + return ( + + {header.title} + + + ); + }); + }; + + if (loading) { + return ; + } + + const renderedActivity = _renderActivites(); + const drawers = _renderDrawers(); + const ths = _renderHeaders(); + + let elements = flatten(zip(renderedActivity, drawers)); + if (!elements.length) { + elements = {noActivityMessage}; + } + + return ( + + + + {ths} + + + + {elements} + +
    +
    + ); +}; + +ActivityTable.propTypes = { + loading: PropTypes.bool, + activity: PropTypes.array, + headers: PropTypes.array, + noActivityMessage: PropTypes.string, + toggleDrawer: PropTypes.func +}; + +export default (ActivityTable); diff --git a/app/assets/javascripts/components/activity/activity_table_row.jsx b/app/assets/javascripts/components/activity/activity_table_row.jsx new file mode 100644 index 0000000000..5ac6155d2e --- /dev/null +++ b/app/assets/javascripts/components/activity/activity_table_row.jsx @@ -0,0 +1,83 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import DiffViewer from '../revisions/diff_viewer.jsx'; +import { toggleUI } from '../../actions'; +import { useDispatch } from 'react-redux'; + +const ActivityTableRow = ({ isOpen, diffUrl, revisionDateTime, + revisionScore, reportUrl, revision, rowId, articleUrl, title, talkPageLink, + author }) => { + const dispatch = useDispatch(); + + const openDrawer = () => { + return dispatch(toggleUI(`drawer_${rowId}`)); + }; + + let revDateElement; + let col2; + const className = isOpen ? 'open' : 'closed'; + + if (diffUrl) { + revDateElement = ( + {revisionDateTime} + ); + } + + if (revisionScore) { + col2 = ( + + {revisionScore} + + ); + } + + if (reportUrl) { + col2 = ( + + {I18n.t('recent_activity.report')} + + ); + } + + let diffViewer; + if (revision && revision.api_url) { + diffViewer = ; + } + + return ( + + + {title} + + {col2} + + {author} + + + {revDateElement} + + + {diffViewer} + + + ); +}; + +ActivityTableRow.propTypes = { + rowId: PropTypes.number, + diffUrl: PropTypes.string, + revisionDateTime: PropTypes.string, + reportUrl: PropTypes.string, + revisionScore: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.number + ]), + articleUrl: PropTypes.string, + talkPageLink: PropTypes.string, + author: PropTypes.string, + title: PropTypes.string, + revision: PropTypes.object, + isOpen: PropTypes.bool, +}; + +export default ActivityTableRow; From 482e06df56a947731a765a9ab57199b05f437eab Mon Sep 17 00:00:00 2001 From: Gabina Luz Bianchi Date: Mon, 13 Jan 2025 23:03:27 -0300 Subject: [PATCH 12/25] Revert "Fix typos in training markup, add script for making a training .docx" This reverts commit 751d8a0256ec5f22706dd12f74d3c643290f78f3. --- .../training_content_to_docx.rb | 27 ------------------- .../6003-stage-1-bibliography.yml | 2 +- .../6503-stage-1-bibliography-no-sandbox.yml | 2 +- 3 files changed, 2 insertions(+), 29 deletions(-) delete mode 100644 docs/training_module_scripts/training_content_to_docx.rb diff --git a/docs/training_module_scripts/training_content_to_docx.rb b/docs/training_module_scripts/training_content_to_docx.rb deleted file mode 100644 index 532391cf5f..0000000000 --- a/docs/training_module_scripts/training_content_to_docx.rb +++ /dev/null @@ -1,27 +0,0 @@ - - # Script to create a Google Doc for reviewing and preparing edits for training modules. - - def html_from_slide(slide) - "\n

    #{slide.title}


    " << - PandocRuby.convert(slide.content, from: :markdown_github, to: :html) << - "
    " - end - - output = '' - -TrainingModule.all.each do |tm| - output += "---

    Training Module ##{tm.id}: #{tm.name}


    ---" - output += "\n

    #{tm.description}


    " - tm.slides.each do |slide| - output += html_from_slide(slide) - end -end - -File.open('training_content.html', 'wb') { |file| file.write(output) } - -# The pandoc conversion fails if a local asset file from the html does not exist. -# As of January 2025, the only case of this is the inline icon in slide 334-authorship-highlighting.yml -# Edit the html file to turn it into an absolute path — https://dashboard.wikiedu.org/assets/images/article-viewer.svg -# then proceed with the conversion. - -`pandoc training_content.html --to docx --output trainings.docx` \ No newline at end of file diff --git a/training_content/wiki_ed/slides/60-keeping-track-of-your-work/6003-stage-1-bibliography.yml b/training_content/wiki_ed/slides/60-keeping-track-of-your-work/6003-stage-1-bibliography.yml index 4bcc294ae9..d2a8633f9a 100644 --- a/training_content/wiki_ed/slides/60-keeping-track-of-your-work/6003-stage-1-bibliography.yml +++ b/training_content/wiki_ed/slides/60-keeping-track-of-your-work/6003-stage-1-bibliography.yml @@ -4,7 +4,7 @@ summary: content: |
    -
    + - + Date: Mon, 13 Jan 2025 23:03:27 -0300 Subject: [PATCH 13/25] Revert "Localisation updates from https://translatewiki.net." This reverts commit f0392b986864e932224efa29282062732f89845a. --- config/locales/pa.yml | 4 ++-- config/locales/se.yml | 5 ----- config/locales/smn.yml | 3 --- config/locales/sms.yml | 10 ++-------- 4 files changed, 4 insertions(+), 18 deletions(-) diff --git a/config/locales/pa.yml b/config/locales/pa.yml index 0b17dfa9d5..fc8e8430a1 100644 --- a/config/locales/pa.yml +++ b/config/locales/pa.yml @@ -44,7 +44,7 @@ pa: sign_up_wikipedia: ਜਾਂ ਵਿਕੀਪੀਡੀਆ 'ਤੇ ਸਾਈਨ ਅੱਪ ਕਰੋ sign_up_log_in_extended: (ਵਿਕੀਪੀਡੀਆ ਨਾਲ) sign_up: ਖਾਤਾ ਬਣਾਓ - submit: ਹਵਾਲੇ ਕਰੋ + submit: ਸਪੁਰਦ ਕਰੋ training: ਸਿਖਲਾਈ change: ਬਦਲੋ details: ਵੇਰਵੇ @@ -250,7 +250,7 @@ pa: show_options: ਵਿਕਲਪ ਦਿਖਾਓ subheading_message: ਆਓ ਕੰਮ ਕਰਨ ਲਈ ਇੱਕ ਵਿਕੀਪੀਡੀਆ ਲੇਖ ਲੱਭੀਏ। subheading_message_wikidata: ਆਓ ਕੰਮ ਕਰਨ ਲਈ ਇੱਕ ਵਿਕੀਡਾਟਾ ਆਈਟਮ ਲੱਭੀਏ। - submit: ਹਵਾਲੇ ਕਰੋ + submit: ਸਪੁਰਦ ਕਰੋ tools: ਸੰਦ training_status: completed: ਪੂਰਾ ਹੋਇਆ diff --git a/config/locales/se.yml b/config/locales/se.yml index 7cd94eced9..abbcbada41 100644 --- a/config/locales/se.yml +++ b/config/locales/se.yml @@ -104,7 +104,6 @@ se: creator: save_cloned_course: Vurke scoping_methods: - categories: Kategoriijat templates: Mállet student_editors: Geavaheaddjit students: Geavaheaddjit @@ -125,7 +124,6 @@ se: article: Artihkal file: Fiila page: Siidu - book: Girji recent_activity: file_name: Fiilanamma revisions: @@ -159,7 +157,6 @@ se: update_username: label: Ođđa geavaheaddjinamma uploads: - categories: Kategoriijat file_name: Fiilanamma license: 'Liseansa:' users: @@ -181,6 +178,4 @@ se: training_status: continue: Joatkke view: Čájet - notes: - save_note: Ruõkk ... diff --git a/config/locales/smn.yml b/config/locales/smn.yml index 3256dec21d..4a63584423 100644 --- a/config/locales/smn.yml +++ b/config/locales/smn.yml @@ -94,7 +94,6 @@ smn: creator: save_cloned_course: Vuorkkii scoping_methods: - categories: Luokah templates: Myenstereh editable: cancel: Jooskâ @@ -107,7 +106,6 @@ smn: upload_count: Vuorkkiimeh Commonsin removed: Sikkum namespace: - book: Kirje lexeme: Lekseem recent_activity: image: Kove @@ -136,7 +134,6 @@ smn: update_username: label: Uđđâ kevtteenommâ uploads: - categories: Luokah image: Kove license: 'Liiseens:' users: diff --git a/config/locales/sms.yml b/config/locales/sms.yml index 0a559030c5..43e2314004 100644 --- a/config/locales/sms.yml +++ b/config/locales/sms.yml @@ -55,7 +55,6 @@ sms: article_link: Artikkel add_available_submit: Lââʹzzet artikkeeʹlid bibliography: Bibliografia - confirm_add_available: Haaʹlääk-a ton tuõđi artikkeeʹl %{title} lââʹzzted? remove: Jaukkâd select: Vaʹlljed campaign: @@ -77,9 +76,9 @@ sms: add_category: Lââʹzzet kategoria add_psid: Lââʹzzet PetScan PSID add_template: Lââʹzzet maall - add_this_category: Lââʹzzet kategoriaid + add_this_category: Lââʹzzet tän kategoria add_this_psid: Lââʹzzet tän PSID - add_this_template: Lââʹzzet maallid + add_this_template: Lââʹzzet tän maall articles_count: Artikkelmieʹrr name: Nõmm category_name: Kategorianõmm @@ -144,7 +143,6 @@ sms: find: Ooʒʒ prograamm save_cloned_course: Ruõkk scoping_methods: - categories: Kategoria templates: Maall delete_course: Jaukkâd prograamm explore: Ooʒʒ prograammi @@ -169,7 +167,6 @@ sms: project: Projeʹktt file: Teâttõs category: Kategoria - book: Ǩeʹrjj recent_activity: article_title: Nõmm image: Kaart da snimldõõǥǥ @@ -209,7 +206,6 @@ sms: update_username: label: Ođđ õõʹnninõmm uploads: - categories: Kategoria file_name: Teâttõsnõmm image: Kartt leʼbe snimldõk label: Ruõkkmõõžž @@ -220,7 +216,6 @@ sms: contribution_statistics: Muʹttemstatistiikk course_passcode: 'Peittsääʹnn:' edits: muttâz - enroll_confirmation: Haaʹlääk-a ton tuõđi õõʹnni %{username} lââʹzzted? first_name: Risttnõmm last_name: Sokknõmm name: Nõmm @@ -230,7 +225,6 @@ sms: one: '%{count} artikkel' other: '%{count} artikkeeʹl' references_count: Lââʹzztum teâttkääiv - remove_confirmation: Haaʹlääk-a ton tuõđi õõʹnni %{username} jaukkeed? training_module_status: Status username: Õõʹnninõmm username_placeholder: Õõʹnninõmm From a9d722cd4c1210fdcc81d54294393511d52770a9 Mon Sep 17 00:00:00 2001 From: Gabina Luz Bianchi Date: Mon, 13 Jan 2025 23:03:27 -0300 Subject: [PATCH 14/25] Revert "fix: Replaced static error count with dynamically generated error count in update_course_stats_spec" This reverts commit b15488aeccf60afdee23195fd6de317f93e73980. --- lib/lift_wing_api.rb | 6 +++--- spec/services/update_course_stats_spec.rb | 14 ++++---------- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/lib/lift_wing_api.rb b/lib/lift_wing_api.rb index 47ce0ccd53..7e3b949b2b 100644 --- a/lib/lift_wing_api.rb +++ b/lib/lift_wing_api.rb @@ -20,8 +20,6 @@ class LiftWingApi # All the wikis with an articlequality model as of 2023-06-28 # https://wikitech.wikimedia.org/wiki/Machine_Learning/LiftWingq AVAILABLE_WIKIPEDIAS = %w[en eu fa fr gl nl pt ru sv tr uk].freeze - # config/initializers/retry_config.rb - RETRY_COUNT = 5 def self.valid_wiki?(wiki) return true if wiki.project == 'wikidata' @@ -53,6 +51,7 @@ def get_revision_data(rev_ids) end log_error_batch(rev_ids) + return results end @@ -61,7 +60,7 @@ def get_revision_data(rev_ids) # Returns a hash with wp10, features, deleted, and prediction, or empty hash if # there is an error. def get_single_revision_parsed_data(rev_id) - tries ||= RETRY_COUNT + tries ||= 5 body = { rev_id:, extended_output: true }.to_json response = lift_wing_server.post(quality_query_url, body) parsed_response = Oj.load(response.body) @@ -70,6 +69,7 @@ def get_single_revision_parsed_data(rev_id) return { 'wp10' => nil, 'features' => nil, 'deleted' => deleted?(parsed_response), 'prediction' => nil } end + build_successful_response(rev_id, parsed_response) rescue StandardError => e tries -= 1 diff --git a/spec/services/update_course_stats_spec.rb b/spec/services/update_course_stats_spec.rb index aa09fd3d6c..361c74ecff 100644 --- a/spec/services/update_course_stats_spec.rb +++ b/spec/services/update_course_stats_spec.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + require 'rails_helper' describe UpdateCourseStats do @@ -80,18 +81,13 @@ it 'tracks update errors properly in Replica' do allow(Sentry).to receive(:capture_exception) - # Stub the constant RETRY_COUNT for this test to ensure retries are controlled - stub_const('LiftWingApi::RETRY_COUNT', 1) - # Raising errors only in Replica stub_request(:any, %r{https://replica-revision-tools.wmcloud.org/.*}).to_raise(Errno::ECONNREFUSED) VCR.use_cassette 'course_update/replica' do subject end sentry_tag_uuid = subject.sentry_tag_uuid - expected_error_count = subject.error_count - - expect(course.flags['update_logs'][1]['error_count']).to eq expected_error_count + expect(course.flags['update_logs'][1]['error_count']).to eq 1 expect(course.flags['update_logs'][1]['sentry_tag_uuid']).to eq sentry_tag_uuid # Checking whether Sentry receives correct error and tags as arguments @@ -104,20 +100,18 @@ it 'tracks update errors properly in LiftWing' do allow(Sentry).to receive(:capture_exception) - stub_const('LiftWingApi::RETRY_COUNT', 1) # Raising errors only in LiftWing stub_request(:any, %r{https://api.wikimedia.org/service/lw.*}).to_raise(Faraday::ConnectionFailed) VCR.use_cassette 'course_update/lift_wing_api' do subject end sentry_tag_uuid = subject.sentry_tag_uuid - expected_error_count = subject.error_count - expect(course.flags['update_logs'][1]['error_count']).to eq expected_error_count + expect(course.flags['update_logs'][1]['error_count']).to eq 8 expect(course.flags['update_logs'][1]['sentry_tag_uuid']).to eq sentry_tag_uuid # Checking whether Sentry receives correct error and tags as arguments expect(Sentry).to have_received(:capture_exception) - .exactly(expected_error_count).times.with(Faraday::ConnectionFailed, anything) + .exactly(8).times.with(Faraday::ConnectionFailed, anything) expect(Sentry).to have_received(:capture_exception) .exactly(8).times.with anything, hash_including(tags: { update_service_id: sentry_tag_uuid, course: course.slug }) From 3870e5aada8194bdde8e7584b33a6d95c3f73d02 Mon Sep 17 00:00:00 2001 From: Gabina Luz Bianchi Date: Mon, 13 Jan 2025 23:03:27 -0300 Subject: [PATCH 15/25] Revert "@fix: stubbed api request and updated test for LiftWing, reference_counter, and revision_score_api" This reverts commit 7ea45a9a993749f0cc6d419d902fe5b42796a4b6. --- spec/lib/lift_wing_api_spec.rb | 15 +- spec/lib/reference_counter_api_spec.rb | 21 +-- spec/lib/revision_score_api_handler_spec.rb | 98 ++++++------ spec/support/request_helpers.rb | 156 -------------------- 4 files changed, 53 insertions(+), 237 deletions(-) diff --git a/spec/lib/lift_wing_api_spec.rb b/spec/lib/lift_wing_api_spec.rb index 737483e39b..487fbc9f29 100644 --- a/spec/lib/lift_wing_api_spec.rb +++ b/spec/lib/lift_wing_api_spec.rb @@ -25,6 +25,9 @@ # Get revision data for valid rev ids for English Wikipedia let(:subject0) { lift_wing_api_class_en_wiki.get_revision_data(rev_ids) } + # Get revision data for valid rev ids for Wikidata + let(:subject1) { described_class.new(wiki).get_revision_data(rev_ids) } + # Get revision data for deleted rev ids for English Wikipedia let(:subject2) { lift_wing_api_class_en_wiki.get_revision_data([deleted_rev_id]) } @@ -44,16 +47,8 @@ end end - context 'fetch json data from api.wikimedia.org' do - before do - stub_wiki_validation - stub_lift_wing_response - end - - # Get revision data for valid rev ids for Wikidata - let(:subject1) { described_class.new(wiki).get_revision_data([829840084, 829840085]) } - - it 'fetches data for wikidata' do + it 'fetches json from api.wikimedia.org for wikidata' do + VCR.use_cassette 'liftwing_api/wikidata' do expect(subject1).to be_a(Hash) expect(subject1.dig('829840084')).to have_key('wp10') expect(subject1.dig('829840084', 'wp10')).to eq(nil) diff --git a/spec/lib/reference_counter_api_spec.rb b/spec/lib/reference_counter_api_spec.rb index 69d3ee1784..0b4cd20e7c 100644 --- a/spec/lib/reference_counter_api_spec.rb +++ b/spec/lib/reference_counter_api_spec.rb @@ -11,7 +11,6 @@ let(:wikidata) { Wiki.get_or_create(language: nil, project: 'wikidata') } let(:deleted_rev_ids) { [708326238] } let(:rev_ids) { [5006940, 5006942, 5006946] } - let(:response) { stub_reference_counter_response } it 'raises InvalidProjectError if using wikidata project' do expect do @@ -19,20 +18,12 @@ end.to raise_error(described_class::InvalidProjectError) end - context 'returns the number of references' do - before do - stub_wiki_validation - stub_reference_counter_response - end - - # Get revision data for valid rev ids for Wikidata - it 'if response is 200 OK', vcr: true do - ref_counter_api = described_class.new(es_wiktionary) - response = ref_counter_api.get_number_of_references_from_revision_ids rev_ids - expect(response.dig('5006940', 'num_ref')).to eq(10) - expect(response.dig('5006942', 'num_ref')).to eq(4) - expect(response.dig('5006946', 'num_ref')).to eq(2) - end + it 'returns the number of references if response is 200 OK', vcr: true do + ref_counter_api = described_class.new(es_wiktionary) + response = ref_counter_api.get_number_of_references_from_revision_ids rev_ids + expect(response.dig('5006940', 'num_ref')).to eq(10) + expect(response.dig('5006942', 'num_ref')).to eq(4) + expect(response.dig('5006946', 'num_ref')).to eq(2) end # it 'logs the message if response is not 200 OK', vcr: true do diff --git a/spec/lib/revision_score_api_handler_spec.rb b/spec/lib/revision_score_api_handler_spec.rb index c77c6461d6..2292f50f7b 100644 --- a/spec/lib/revision_score_api_handler_spec.rb +++ b/spec/lib/revision_score_api_handler_spec.rb @@ -9,7 +9,7 @@ let(:subject) { handler.get_revision_data [829840090, 829840091] } describe '#get_revision_data' do - it 'returns completed scores if data is retrieved without errors' do + it 'returns completed scores if retrieves data without errors' do VCR.use_cassette 'revision_score_api_handler/en_wikipedia' do expect(subject).to be_a(Hash) expect(subject.dig('829840090', 'wp10').to_f).to be_within(0.01).of(62.81) @@ -28,26 +28,15 @@ end end - describe 'error hitting LiftWingApi' do - before do - stub_wiki_validation - stub_revision_score_reference_counter_reponse - end - - let(:wiki) { create(:wiki, project: 'wikipedia', language: 'es') } - let(:handler) { described_class.new(wiki:) } - let(:subject) { handler.get_revision_data [829840090, 829840091] } - - it 'returns completed scores if there is an error hitting LiftWingApi' do - VCR.use_cassette 'revision_score_api_handler/en_wikipedia_liftwing_error' do - stub_request(:any, /.*api.wikimedia.org.*/) - .to_raise(Errno::ETIMEDOUT) - expect(subject).to be_a(Hash) - expect(subject.dig('829840090')).to eq({ 'wp10' => nil, - 'features' => { 'num_ref' => 132 }, 'deleted' => false, 'prediction' => nil }) - expect(subject.dig('829840091')).to eq({ 'wp10' => nil, - 'features' => { 'num_ref' => 1 }, 'deleted' => false, 'prediction' => nil }) - end + it 'returns completed scores if there is an error hitting LiftWingApi' do + VCR.use_cassette 'revision_score_api_handler/en_wikipedia_liftwing_error' do + stub_request(:any, /.*api.wikimedia.org.*/) + .to_raise(Errno::ETIMEDOUT) + expect(subject).to be_a(Hash) + expect(subject.dig('829840090')).to eq({ 'wp10' => nil, + 'features' => { 'num_ref' => 132 }, 'deleted' => false, 'prediction' => nil }) + expect(subject.dig('829840091')).to eq({ 'wp10' => nil, + 'features' => { 'num_ref' => 1 }, 'deleted' => false, 'prediction' => nil }) end end @@ -87,36 +76,34 @@ end context 'when the wiki is available only for LiftWing API' do + before { stub_wiki_validation } + let(:wiki) { create(:wiki, project: 'wikidata', language: nil) } let(:handler) { described_class.new(wiki:) } - - before do - stub_wiki_validation - stub_revision_score_lift_wing_reponse - end + let(:subject) { handler.get_revision_data [144495297, 144495298] } describe '#get_revision_data' do - let(:subject) { handler.get_revision_data [144495297, 144495298] } - - it 'returns completed scores if data is retrieved without errors' do - expect(subject).to be_a(Hash) - expect(subject.dig('144495297', 'wp10').to_f).to eq(0) - expect(subject.dig('144495297', 'features')).to be_a(Hash) - expect(subject.dig('144495297', 'features', - 'feature.len()')).to eq(2) - # 'num_ref' key doesn't exist for wikidata features - expect(subject.dig('144495297', 'features').key?('num_ref')).to eq(false) - expect(subject.dig('144495297', 'deleted')).to eq(false) - expect(subject.dig('144495297', 'prediction')).to eq('D') - - expect(subject.dig('144495298', 'wp10').to_f).to eq(0) - expect(subject.dig('144495298', 'features')).to be_a(Hash) - expect(subject.dig('144495298', 'features', - 'feature.len()')).to eq(0) - # 'num_ref' key doesn't exist for wikidata features - expect(subject.dig('144495298', 'features').key?('num_ref')).to eq(false) - expect(subject.dig('144495298', 'deleted')).to eq(false) - expect(subject.dig('144495298', 'prediction')).to eq('E') + it 'returns completed scores if retrieves data without errors' do + VCR.use_cassette 'revision_score_api_handler/wikidata' do + expect(subject).to be_a(Hash) + expect(subject.dig('144495297', 'wp10').to_f).to eq(0) + expect(subject.dig('144495297', 'features')).to be_a(Hash) + expect(subject.dig('144495297', 'features', + 'feature.len()')).to eq(2) + # 'num_ref' key doesn't exist for wikidata features + expect(subject.dig('144495297', 'features').key?('num_ref')).to eq(false) + expect(subject.dig('144495297', 'deleted')).to eq(false) + expect(subject.dig('144495297', 'prediction')).to eq('D') + + expect(subject.dig('144495298', 'wp10').to_f).to eq(0) + expect(subject.dig('144495298', 'features')).to be_a(Hash) + expect(subject.dig('144495298', 'features', + 'feature.len()')).to eq(0) + # 'num_ref' key doesn't exist for wikidata features + expect(subject.dig('144495298', 'features').key?('num_ref')).to eq(false) + expect(subject.dig('144495298', 'deleted')).to eq(false) + expect(subject.dig('144495298', 'prediction')).to eq('E') + end end it 'returns completed scores if there is an error hitting LiftWingApi' do @@ -132,10 +119,7 @@ end context 'when the wiki is available only for reference-counter API' do - before do - stub_wiki_validation - stub_revision_score_reference_counter_reponse - end + before { stub_wiki_validation } let(:wiki) { create(:wiki, project: 'wikipedia', language: 'es') } let(:handler) { described_class.new(wiki:) } @@ -143,11 +127,13 @@ describe '#get_revision_data' do it 'returns completed scores if retrieves data without errors' do - expect(subject).to be_a(Hash) - expect(subject.dig('157412237')).to eq({ 'wp10' => nil, - 'features' => { 'num_ref' => 111 }, 'deleted' => false, 'prediction' => nil }) - expect(subject.dig('157417768')).to eq({ 'wp10' => nil, - 'features' => { 'num_ref' => 42 }, 'deleted' => false, 'prediction' => nil }) + VCR.use_cassette 'revision_score_api_handler/es_wikipedia' do + expect(subject).to be_a(Hash) + expect(subject.dig('157412237')).to eq({ 'wp10' => nil, + 'features' => { 'num_ref' => 111 }, 'deleted' => false, 'prediction' => nil }) + expect(subject.dig('157417768')).to eq({ 'wp10' => nil, + 'features' => { 'num_ref' => 42 }, 'deleted' => false, 'prediction' => nil }) + end end it 'returns completed scores if there is an error hitting reference-counter api' do diff --git a/spec/support/request_helpers.rb b/spec/support/request_helpers.rb index 56e9d54859..347b81e874 100644 --- a/spec/support/request_helpers.rb +++ b/spec/support/request_helpers.rb @@ -1,5 +1,4 @@ # frozen_string_literal: true -require 'json' # Ensure JSON is required for to_json #= Stubs for various requests module RequestHelpers @@ -562,159 +561,4 @@ def stub_course stub_timeline stub_users end - - def stub_lift_wing_response - request_body = { - 'wikidatawiki' => { - 'models' => { - 'itemquality' => { - 'version' => '0.5.0' - } - }, - 'scores' => { - '829840084' => { - 'itemquality' => { - 'score' => { - 'prediction' => 'D', - 'probability' => { 'A' => 0.001863543366261331, 'B' => 0.001863543366261331 } - }, - 'features' => { - 'feature.len()' => 3.0, - 'feature.len()' => 3.0, - 'feature.len()' => 0.0 - } - } - }, - '829840085' => { - 'itemquality' => { - 'score' => { - 'prediction' => 'D', - 'probability' => { 'A' => 0.005396336449201622, 'B' => 0.005396336449201622 } - }, - 'features' => { - 'feature.len()' => 10.0, - 'feature.len()' => 9.0, - 'feature.len()' => 1.0 - } - } - } - } - } - } - stub_request(:post, 'https://api.wikimedia.org/service/lw/inference/v1/models/wikidatawiki-itemquality:predict') - .with( - body: hash_including(extended_output: true), - headers: { 'Content-Type': 'application/json' } - ).to_return( - status: 200, - body: request_body.to_json - ) - end - - def stub_reference_counter_response - # Define the response body in a hash with revision IDs as keys - request_body = { - '5006940' => { 'num_ref' => 10, 'lang' => 'es', 'project' => 'wiktionary', - 'revid' => 5006940 }, - '5006942' => { 'num_ref' => 4, 'lang' => 'es', 'project' => 'wiktionary', - 'revid' => 5006942 }, - '5006946' => { 'num_ref' => 2, 'lang' => 'es', 'project' => 'wiktionary', 'revid' => 5006946 } - } - - # Stub the request to match the revision ID in the URL - stub_request(:get, %r{https://reference-counter.toolforge.org/api/v1/references/wiktionary/es/\d+}) - .to_return( - status: 200, - body: lambda do |request| - # Extract revision ID from the URL - rev_id = request.uri.path.split('/').last - # Return the appropriate response based on the revision ID - { 'num_ref' => request_body[rev_id.to_s]['num_ref'] }.to_json - end, - headers: { 'Content-Type' => 'application/json' } - ) - end - - def stub_revision_score_lift_wing_reponse - request_body = - { - 'wikidatawiki' => { - 'models' => { - 'itemquality' => { - 'version' => '0.5.0' - } - }, - 'scores' => { - '144495297' => { - 'itemquality' => { - 'score' => { - 'prediction' => 'D', - 'probability' => { - 'A' => 0.004943068308984735, - 'B' => 0.004943068308984735 - } - }, - 'features' => { - 'feature.len()' => 3.0, - 'feature.len()' => 3.0, - 'feature.len()' => 2.0, - 'feature.len()' => 2.0 - } - } - }, - '144495298' => { - 'itemquality' => { - 'score' => { - 'prediction' => 'E', - 'probability' => { - 'A' => 0.0006501008909422321, - 'B' => 0.000887054617313177 - } - }, - 'features' => { - 'feature.len()' => 1.0, - 'feature.len()' => 1.0, - 'feature.len()' => 0.0, - 'feature.len()' => 0.0 - } - } - } - } - } - } - stub_request(:post, 'https://api.wikimedia.org/service/lw/inference/v1/models/wikidatawiki-itemquality:predict') - .with( - body: hash_including(extended_output: true), - headers: { 'Content-Type': 'application/json' } - ).to_return( - status: 200, - body: request_body.to_json - ) - end - - def stub_revision_score_reference_counter_reponse - request_body = { - '157412237' => { 'num_ref' => 111, 'lang' => 'es', 'project' => 'wikipedia', - 'revid' => 157412237 }, - '157417768' => { 'num_ref' => 42, 'lang' => 'es', 'project' => 'wikipedia', - 'revid' => 157417768 }, - '829840090' => { 'num_ref' => 132, 'lang' => 'es', 'project' => 'wikipedia', - 'revid' => 829840090 }, - '829840091' => { 'num_ref' => 1, 'lang' => 'es', 'project' => 'wikipedia', - 'revid' => 829840091 } - } - - # Stub the request to match the revision ID in the URL - stub_request(:get, %r{https://reference-counter.toolforge.org/api/v1/references/wikipedia/es/\d+}) - .to_return( - status: 200, - body: lambda do |request| - # Extract revision ID from the URL - rev_id = request.uri.path.split('/').last - # Return the appropriate response based on the revision ID - { 'num_ref' => request_body[rev_id.to_s]['num_ref'] }.to_json - end, - headers: { 'Content-Type' => 'application/json' } - ) - end end From e01bf47f22eba1e7a832a63f27e2714edfcc13b3 Mon Sep 17 00:00:00 2001 From: Gabina Luz Bianchi Date: Mon, 13 Jan 2025 23:03:27 -0300 Subject: [PATCH 16/25] Revert "Send reminder email to new non-instructors who complete onboarding but don't join a course" This reverts commit 0c08b74696ab7c97470a1e47f771aeef13c2bd26. --- app/controllers/onboarding_controller.rb | 1 - app/mailers/enrollment_reminder_mailer.rb | 14 ---------- .../email.html.haml | 27 ------------------- .../enrollment_reminder_email_worker.rb | 25 ----------------- .../enrollment_reminder_mailer_preview.rb | 13 --------- 5 files changed, 80 deletions(-) delete mode 100644 app/mailers/enrollment_reminder_mailer.rb delete mode 100644 app/views/enrollment_reminder_mailer/email.html.haml delete mode 100644 app/workers/enrollment_reminder_email_worker.rb delete mode 100644 spec/mailers/previews/enrollment_reminder_mailer_preview.rb diff --git a/app/controllers/onboarding_controller.rb b/app/controllers/onboarding_controller.rb index 245701903b..28f5680c8c 100644 --- a/app/controllers/onboarding_controller.rb +++ b/app/controllers/onboarding_controller.rb @@ -22,7 +22,6 @@ def onboard permissions: @permissions, onboarded: true) update_real_names_on_courses if Features.wiki_ed? - EnrollmentReminderEmailWorker.schedule_reminder(@user) CheckWikiEmailWorker.check(user: @user) head :no_content end diff --git a/app/mailers/enrollment_reminder_mailer.rb b/app/mailers/enrollment_reminder_mailer.rb deleted file mode 100644 index 5e5d1504cd..0000000000 --- a/app/mailers/enrollment_reminder_mailer.rb +++ /dev/null @@ -1,14 +0,0 @@ -# frozen_string_literal: true - -class EnrollmentReminderMailer < ApplicationMailer - def self.send_reminder(user) - return unless Features.email? && Features.wiki_ed? - return if user.email.nil? - email(user).deliver_now - end - - def email(user) - @user = user - mail(to: @user.email, subject: 'Next steps on Wiki Education Dashboard') - end -end diff --git a/app/views/enrollment_reminder_mailer/email.html.haml b/app/views/enrollment_reminder_mailer/email.html.haml deleted file mode 100644 index 4e74f66e2c..0000000000 --- a/app/views/enrollment_reminder_mailer/email.html.haml +++ /dev/null @@ -1,27 +0,0 @@ -%link{rel: 'stylesheet', href:'/mailer.css'} -%table.row - %tbody - %tr - %th - %table - %tr - %td.main-content - %p.paragraph - = "Hello #{@user.username}!" - %p.paragraph - Welcome to - %a.link{:href => "https://#{ENV['dashboard_url']}"} - Wiki Education Dashboard! - %p.paragraph - You've signed in to the Dashboard using your Wikipedia account, but - you haven't joined a course. If you are a student and you were given - an enrollment link by your instructor, you can now use that link - to add yourself to the course page. - %p.paragraph - If you're here for another reason, or you've run into technical difficulties, - let us know by replying to this email. - %p.paragraph - Best regards, - %br - %em - The Wiki Education team \ No newline at end of file diff --git a/app/workers/enrollment_reminder_email_worker.rb b/app/workers/enrollment_reminder_email_worker.rb deleted file mode 100644 index cee1b824b2..0000000000 --- a/app/workers/enrollment_reminder_email_worker.rb +++ /dev/null @@ -1,25 +0,0 @@ -# frozen_string_literal: true - -class EnrollmentReminderEmailWorker - include Sidekiq::Worker - sidekiq_options lock: :until_executed, - retry: 0 # Move job to the 'dead' queue if it fails - - def self.schedule_reminder(user) - # We only use this for users who didn't indicate they are instructors, - # as it is intended to prompt students to use the enrollment link - # in case something in the enrollment flow went wrong. - return unless user.permissions == User::Permissions::NONE - # Also make sure we don't spam people who revisit the onboarding flow. - return if user.created_at < 1.day.ago - - perform_at(5.minutes.from_now, user.id) - end - - def perform(user_id) - user = User.find user_id - return if user.courses.any? - - EnrollmentReminderMailer.send_reminder(user) - end -end diff --git a/spec/mailers/previews/enrollment_reminder_mailer_preview.rb b/spec/mailers/previews/enrollment_reminder_mailer_preview.rb deleted file mode 100644 index 1df2e243aa..0000000000 --- a/spec/mailers/previews/enrollment_reminder_mailer_preview.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -class EnrollmentReminderMailerPreview < ActionMailer::Preview - def enrollment_reminder_email - EnrollmentReminderMailer.email(example_user) - end - - private - - def example_user - User.new(email: 'sage@example.com', username: 'Ragesoss') - end -end From 400f7a3fb26f404c95df8f7fce423c6651072efd Mon Sep 17 00:00:00 2001 From: Gabina Luz Bianchi Date: Mon, 13 Jan 2025 23:03:27 -0300 Subject: [PATCH 17/25] Revert "fix: update slide removal logic for conditional survey questions" This reverts commit 34dd8082ca09bc54e0ad5998629faf416db41fe3. --- .../javascripts/surveys/modules/Survey.js | 105 ++++++++---------- spec/features/survey_bugs_spec.rb | 10 +- 2 files changed, 52 insertions(+), 63 deletions(-) diff --git a/app/assets/javascripts/surveys/modules/Survey.js b/app/assets/javascripts/surveys/modules/Survey.js index 2aad692baa..dc8dab9f88 100644 --- a/app/assets/javascripts/surveys/modules/Survey.js +++ b/app/assets/javascripts/surveys/modules/Survey.js @@ -698,45 +698,50 @@ const Survey = { } }, - // To remove a conditional question from the flow if the condition that it depends on has changed. - resetConditionalGroupChildren(conditionalGroup) { - const { children, currentAnswers } = conditionalGroup; - - if ((typeof currentAnswers !== 'undefined' && currentAnswers !== null) && currentAnswers.length) { - const excludeFromReset = []; - currentAnswers.forEach((a) => { excludeFromReset.push(a); }); - children.forEach((question) => { - const $question = $(question); - let string; - if ($question.data('conditional-question')) { - string = $question.data('conditional-question'); - } else { - string = $question.find('[data-conditional-question]').data('conditional-question'); - } - const { value } = Utils.parseConditionalString(string); - if (excludeFromReset.indexOf(value) === -1) { - this.resetConditionalQuestion($question); - } else { - $question.removeClass('hidden'); - } - }); - } else { - children.forEach((question) => { - this.resetConditionalQuestion($(question)); - if ($(question).hasClass('survey__question-row')) { - const $parentBlock = $(question).parents(BLOCK_CONTAINER_SELECTOR); - const blockIndex = $(question).data('block-index'); - if (!($parentBlock.find('.survey__question-row:not([data-conditional-question])').length > 1)) { - this.resetConditionalQuestion($parentBlock); - if (this.detachedParentBlocks[blockIndex] === undefined) { - this.detachedParentBlocks[blockIndex] = $parentBlock; - this.removeSlide($parentBlock); - $parentBlock.detach(); - } - } - } - }); - } + // FIXME: This is supposed to remove a conditional question from + // the flow if the condition that it depends on has changed. + // However, when this happens it leaves the survey in a state + // with no visible questions and no way to proceed. + // Disabling this feature means that, once inserted, a conditional + // question will not be removed, but that's better than a broken survey. + resetConditionalGroupChildren(/* conditionalGroup */) { + // const { children, currentAnswers } = conditionalGroup; + + // if ((typeof currentAnswers !== 'undefined' && currentAnswers !== null) && currentAnswers.length) { + // const excludeFromReset = []; + // currentAnswers.forEach((a) => { excludeFromReset.push(a); }); + // children.forEach((question) => { + // const $question = $(question); + // let string; + // if ($question.data('conditional-question')) { + // string = $question.data('conditional-question'); + // } else { + // string = $question.find('[data-conditional-question]').data('conditional-question'); + // } + // const { value } = Utils.parseConditionalString(string); + // if (excludeFromReset.indexOf(value) === -1) { + // this.resetConditionalQuestion($question); + // } else { + // $question.removeClass('hidden'); + // } + // }); + // } else { + // children.forEach((question) => { + // this.resetConditionalQuestion($(question)); + // if ($(question).hasClass('survey__question-row')) { + // const $parentBlock = $(question).parents(BLOCK_CONTAINER_SELECTOR); + // const blockIndex = $(question).data('block-index'); + // if (!($parentBlock.find('.survey__question-row:not([data-conditional-question])').length > 1)) { + // this.resetConditionalQuestion($parentBlock); + // if (this.detachedParentBlocks[blockIndex] === undefined) { + // this.detachedParentBlocks[blockIndex] = $parentBlock; + // this.removeSlide($parentBlock); + // $parentBlock.detach(); + // } + // } + // } + // }); + // } }, removeSlide($block) { @@ -748,29 +753,7 @@ const Survey = { if ($question.hasClass('survey__question-row')) { $question.removeAttr('style').addClass('hidden not-seen disabled'); } else { - // Find which question group/slider this question belongs to by climbing up the DOM tree - const $grandParents = $question.parents('[data-question-group-blocks]'); - - // Extract the group's index number so we know which specific slider we need to modify - const questionGroupIndex = $grandParents.data('question-group-blocks'); - - // Get the actual slider jQuery object that we need to remove the question from - const $slider = this.groupSliders[questionGroupIndex]; - - // Get the slide index before detaching - const slideIndex = $question.data('slick-index'); - - // Remove the slide from Slick first - $slider?.slick('slickRemove', slideIndex); - - // Then detach the element $question.detach(); - - // Updates Progress Bar on Top Right of the UI. - this.indexBlocks(); - - // Update Slide Button to Determine whether to show Next or Submit button. - this.updateButtonText(); } $question.find('input[type=text], textarea').val(''); $question.find('input:checked').removeAttr('checked'); diff --git a/spec/features/survey_bugs_spec.rb b/spec/features/survey_bugs_spec.rb index 9e0b02299a..e367f88cd7 100644 --- a/spec/features/survey_bugs_spec.rb +++ b/spec/features/survey_bugs_spec.rb @@ -128,8 +128,14 @@ click_button('Next', visible: true) # Q2 end - sleep 2 - expect(page).to have_content('Submit Survey') + # Now this question ideally should be skipped + # but the code that did that breaks the survey + # by removing the question without sliding + # the next one into view. + find('.label', text: 'Maybe').click + within('div[data-progress-index="4"]') do + click_button('Next', visible: true) # Q3 + end # Now we can actually submit the survey # and finish. From 86ee2c056e38a8b2ceca4dc6d526b357b3494068 Mon Sep 17 00:00:00 2001 From: Gabina Luz Bianchi Date: Mon, 13 Jan 2025 23:03:27 -0300 Subject: [PATCH 18/25] Revert "fix: marked flaky test in multiwiki_assignment_spec as pending" This reverts commit 96e99c68e7ca810815c278079ab6ec85fdfd2bad. --- spec/features/multiwiki_assignment_spec.rb | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/spec/features/multiwiki_assignment_spec.rb b/spec/features/multiwiki_assignment_spec.rb index 118b4be516..d119d009d4 100644 --- a/spec/features/multiwiki_assignment_spec.rb +++ b/spec/features/multiwiki_assignment_spec.rb @@ -48,8 +48,6 @@ end it 'creates valid assignments from multiple article titles' do - pending 'Fails in CI caused by Assign all button not found' - VCR.use_cassette 'multiwiki_assignment' do visit "/courses/#{course.slug}/students/articles" first('.student-selection .student').click @@ -76,8 +74,6 @@ expect(page).to have_css('a[href="https://fr.wikipedia.org/wiki/Anglais"]') expect(page).to have_css('a[href="https://fr.wikipedia.org/wiki/Terre"]') end - - pass_pending_spec end it 'creates a valid assignment from an article and a project and language from tracked Wikis' do @@ -112,8 +108,6 @@ end it 'will create a valid assignment for multilingual wikisource projects' do - pending 'Fails in CI caused by Heyder Cansa content not found' - VCR.use_cassette 'multiwiki_assignment' do visit "/courses/#{course.slug}/students/articles" first('.student-selection .student').click @@ -134,13 +128,9 @@ expect(link[:href]).to include('wikisource') end end - - pass_pending_spec end it 'will create a valid assignment for multilingual wikimedia incubator projects' do - pending 'Fails in CI caused by Wp/kiu/Hey content not found' - VCR.use_cassette 'multiwiki_assignment' do visit "/courses/#{course.slug}/students/articles" first('.student-selection .student').click @@ -161,7 +151,5 @@ expect(link[:href]).to include('incubator.wikimedia') end end - - pass_pending_spec end end From 99e8ce7c591aa7ba4841bb79180981f06eede157 Mon Sep 17 00:00:00 2001 From: Gabina Luz Bianchi Date: Mon, 13 Jan 2025 23:03:27 -0300 Subject: [PATCH 19/25] Revert "refactor remaining violations" This reverts commit 16a90bf3057edbfb8e14b4875c52c63fa8754a1e. --- app/services/sandbox_url_updator.rb | 9 +++------ lib/assignment_manager.rb | 8 +++----- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/app/services/sandbox_url_updator.rb b/app/services/sandbox_url_updator.rb index bc7dd4ac64..a9b2c5bf80 100644 --- a/app/services/sandbox_url_updator.rb +++ b/app/services/sandbox_url_updator.rb @@ -32,11 +32,8 @@ def validate_new_url raise InvalidUrlError, I18n.t('assignments.invalid_url', url: @new_url) unless new_url_match # Handle mismatched wiki new_language, new_project = new_url_match.captures - wiki_matches = (existing_language == new_language && existing_project == new_project) - handle_mismatched_wiki unless wiki_matches - end - - def handle_mismatched_wiki - raise MismatchedWikiError, I18n.t('assignments.mismatched_wiki', url: @new_url) + unless existing_language == new_language && existing_project == new_project # rubocop:disable Style/GuardClause + raise MismatchedWikiError, I18n.t('assignments.mismatched_wiki', url: @new_url) + end end end diff --git a/lib/assignment_manager.rb b/lib/assignment_manager.rb index d1bd7af70f..d999e4c347 100644 --- a/lib/assignment_manager.rb +++ b/lib/assignment_manager.rb @@ -107,12 +107,10 @@ def set_article_from_database def check_wiki_edu_discouraged_article category = Category.find_by(name: ENV['blocked_assignment_category']) - article_discouraged = (category.present? && category.article_titles.include?(@clean_title)) - handle_discouraged_article if article_discouraged - end - def handle_discouraged_article - raise DiscouragedArticleError, I18n.t('assignments.blocked_assignment', title: @clean_title) + if category.present? && category.article_titles.include?(@clean_title) # rubocop:disable Style/GuardClause + raise DiscouragedArticleError, I18n.t('assignments.blocked_assignment', title: @clean_title) + end end def import_article_from_wiki From 82179d5a3222d1237a6de2bf95924e50dd1856b6 Mon Sep 17 00:00:00 2001 From: Gabina Luz Bianchi Date: Mon, 13 Jan 2025 23:03:27 -0300 Subject: [PATCH 20/25] Revert "Update dependency documentation" This reverts commit 7f73e20977fe1bc5519c32d758516fc4e9972312. --- docs/setup.md | 2 +- docs/troubleshooting.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/setup.md b/docs/setup.md index eed8430d67..5d10527a56 100644 --- a/docs/setup.md +++ b/docs/setup.md @@ -24,7 +24,7 @@ For Windows, the easiest way to get an environment set up is to [use Ubuntu with ## Prerequisite There are some basic requirements for the script to work: - git (to clone the repository) -- node version 14 or newer +- node version 14 or 16 - python 3.5 or newer - ruby 3.1.2 - apt (debian) or homebrew (MacOS) diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index e333688461..05b3201769 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -43,7 +43,7 @@ Your system has cmdtest installed, which provides a different program as yarn. U - **To check if redis is running as a daemon in Linux** `ps aux | grep redis-server` -- Use node v14 or newer to avoid any errors. +- Use node v10 or lower to avoid any errors. - **For WSL users , if rspec tests are taking too long to run** make sure to fork the repo in the linux file system and not in the windows partition. Use command `pwd` to know the exact path of your repo. If the path starts with `/mnt/`, the repo is in windows partition. Follow the documentation available at link: https://learn.microsoft.com/en-us/windows/wsl/filesystems to know more about storing and moving files in the linux file system. If you have received error related to dependencies(`sudo apt-get install -y redis-server mariadb-server libmariadb-dev rvm nodejs npm pandoc`), try to install packages one by one and figure out which packages are creating problems. From 893be7fbe4bc683ee91f2922911c9376e413d80a Mon Sep 17 00:00:00 2001 From: Gabina Luz Bianchi Date: Mon, 13 Jan 2025 23:03:27 -0300 Subject: [PATCH 21/25] Revert "Change threshold for ContinuedCourseActivityAlert" This reverts commit 47fd72f99c70e2bcc1d7c3d2b831473745edc920. --- lib/alerts/continued_course_activity_alert_manager.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/alerts/continued_course_activity_alert_manager.rb b/lib/alerts/continued_course_activity_alert_manager.rb index df868b4480..2a8e501f88 100644 --- a/lib/alerts/continued_course_activity_alert_manager.rb +++ b/lib/alerts/continued_course_activity_alert_manager.rb @@ -22,7 +22,7 @@ def create_alerts private - MINIMUM_CHARACTERS_ADDED_AFTER_COURSE_END = 200 + MINIMUM_CHARACTERS_ADDED_AFTER_COURSE_END = 1000 def significant_activity_after_course_end?(course) user_ids = course.students.pluck(:id) post_course_characters = Revision From 2c25fbe441cbddf95c15fdcad8591ba35d339c19 Mon Sep 17 00:00:00 2001 From: Gabina Luz Bianchi Date: Mon, 13 Jan 2025 23:03:27 -0300 Subject: [PATCH 22/25] Revert "Adds guard statements to prevent `NoMethodError`s when `get_user_info`'s `user_data` is `nil` and tests to confirm expected behaviour" This reverts commit 6f890ba0e7a8c7c176841466bc49f9a603935269. --- lib/importers/user_importer.rb | 2 +- lib/wiki_api.rb | 2 +- spec/lib/importers/user_importer_spec.rb | 11 +---------- spec/lib/wiki_api_spec.rb | 12 ------------ 4 files changed, 3 insertions(+), 24 deletions(-) diff --git a/lib/importers/user_importer.rb b/lib/importers/user_importer.rb index cbeab717e8..c1feebbc5a 100644 --- a/lib/importers/user_importer.rb +++ b/lib/importers/user_importer.rb @@ -114,7 +114,7 @@ def self.get_global_id(username) def self.update_user_from_wiki(user, wiki) user_data = WikiApi.new(wiki).get_user_info(user.username) - return if user_data.nil? || user_data['missing'] + return if user_data['missing'] user.update!(username: user_data['name'], registered_at: user_data['registration'], global_id: user_data&.dig('centralids', 'CentralAuth')) diff --git a/lib/wiki_api.rb b/lib/wiki_api.rb index c189327842..65ddce0a7c 100644 --- a/lib/wiki_api.rb +++ b/lib/wiki_api.rb @@ -47,7 +47,7 @@ def get_user_info(username) ususers: username, usprop: 'centralids|registration' } user_data = mediawiki('query', user_query) - return unless user_data&.data&.dig('users')&.any? + return unless user_data.data['users'].any? user_data.data['users'][0] end diff --git a/spec/lib/importers/user_importer_spec.rb b/spec/lib/importers/user_importer_spec.rb index 83ece5ff30..fdb4d596d7 100644 --- a/spec/lib/importers/user_importer_spec.rb +++ b/spec/lib/importers/user_importer_spec.rb @@ -180,16 +180,6 @@ describe '.update_user_from_wiki' do let(:course) { create(:course) } - let(:enwiki) { Wiki.get_or_create(language: 'en', project: 'wikipedia') } - - context 'when get_user_info returns nil' do - it 'returns early without raising an error and does not update the user' do - user = create(:user, username: 'RageSoss') - allow_any_instance_of(WikiApi).to receive(:get_user_info).and_return(nil) - expect(user).not_to receive(:update!) - expect { described_class.update_user_from_wiki(user, enwiki) }.not_to raise_error - end - end it 'cleans up records when there are collisions' do VCR.use_cassette 'user/new_from_renamed_user' do @@ -207,6 +197,7 @@ it 'sets the registration date from English Wikipedia' do VCR.use_cassette 'user/enwiki_only_account' do user = create(:user, username: 'Brady2421') + enwiki = Wiki.get_or_create(language: 'en', project: 'wikipedia') described_class.update_user_from_wiki(user, enwiki) expect(user.registered_at).not_to be_nil end diff --git a/spec/lib/wiki_api_spec.rb b/spec/lib/wiki_api_spec.rb index 601612cf97..73ac618f1a 100644 --- a/spec/lib/wiki_api_spec.rb +++ b/spec/lib/wiki_api_spec.rb @@ -169,18 +169,6 @@ class UnexpectedError < StandardError; end end end - describe '#get_user_info' do - let(:wiki) { Wiki.new(language: 'en', project: 'wikipedia') } - - context 'when mediawiki query returns nil' do - it 'returns early without raising an error' do - allow_any_instance_of(described_class).to receive(:mediawiki).and_return(nil) - expect { described_class.new.get_user_info('Ragesoss') }.not_to raise_error - expect(described_class.new.get_user_info('Ragesoss')).to be_nil - end - end - end - describe '#redirect?' do let(:wiki) { Wiki.new(language: 'en', project: 'wikipedia') } let(:subject) { described_class.new(wiki).redirect?(title) } From 7719e5ee417b45c058c2493f4618b98be952f05f Mon Sep 17 00:00:00 2001 From: Gabina Luz Bianchi Date: Mon, 13 Jan 2025 23:03:27 -0300 Subject: [PATCH 23/25] Revert "fix guard clause violations" This reverts commit bfbd344c948f742ff8b8dc03713ec89561807b9f. --- .rubocop.yml | 2 ++ app/controllers/courses_controller.rb | 13 ++++++----- .../requested_accounts_controller.rb | 9 ++++---- app/helpers/article_helper.rb | 23 +++++++++++++------ app/models/campaign.rb | 7 +++--- app/services/add_sandbox_template.rb | 9 ++++++-- app/services/sandbox_url_updator.rb | 2 +- lib/assignment_manager.rb | 2 +- lib/list_course_manager.rb | 11 +++++---- lib/reference_counter_api.rb | 15 +++++++----- lib/revision_feedback_service.rb | 5 ++-- lib/revision_score_api_handler.rb | 5 ++-- lib/training_module_due_date_manager.rb | 7 ++++-- 13 files changed, 69 insertions(+), 41 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 80144a1092..9fe6c64747 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -123,6 +123,8 @@ Rails/FilePath: Enabled: false Performance/UnfreezeString: Enabled: false +Style/GuardClause: + Enabled: false Rails/HasManyOrHasOneDependent: Enabled: false Rails/InverseOf: diff --git a/app/controllers/courses_controller.rb b/app/controllers/courses_controller.rb index 39aa038719..65941982a6 100644 --- a/app/controllers/courses_controller.rb +++ b/app/controllers/courses_controller.rb @@ -421,12 +421,13 @@ def update_timeslice_duration def update_last_reviewed username = params.dig(:course, 'last_reviewed', 'username') timestamp = params.dig(:course, 'last_reviewed', 'timestamp') - return unless username && timestamp - @course.flags['last_reviewed'] = { - 'username' => username, - 'timestamp' => timestamp - } - @course.save + if username && timestamp + @course.flags['last_reviewed'] = { + 'username' => username, + 'timestamp' => timestamp + } + @course.save + end end def handle_post_course_creation_updates diff --git a/app/controllers/requested_accounts_controller.rb b/app/controllers/requested_accounts_controller.rb index a38740ac68..561651570b 100644 --- a/app/controllers/requested_accounts_controller.rb +++ b/app/controllers/requested_accounts_controller.rb @@ -130,9 +130,10 @@ def passcode_valid? def handle_existing_request existing_request = RequestedAccount.find_by(course: @course, username: params[:username]) - return unless existing_request - existing_request.update(email: params[:email]) - render json: { message: existing_request.updated_email_message } - yield + if existing_request + existing_request.update(email: params[:email]) + render json: { message: existing_request.updated_email_message } + yield + end end end diff --git a/app/helpers/article_helper.rb b/app/helpers/article_helper.rb index 5c87ac617a..949989e311 100644 --- a/app/helpers/article_helper.rb +++ b/app/helpers/article_helper.rb @@ -35,17 +35,26 @@ def rating_priority(rating) def rating_display(rating) rating = default_class(rating) return nil if rating.nil? - return rating if %w[fa ga fl].include? rating - return rating[0] # use the first letter of the rating as the abbreviated version + if %w[fa ga fl].include? rating + return rating + else + return rating[0] # use the first letter of the rating as the abbreviated version + end end def default_class(rating) # Handles the different article classes and returns a known article class - return rating if %w[fa fl a ga b c start stub list].include? rating - return 'b' if rating.eql? 'bplus' - return 'a' if rating.eql? 'a/ga' - return 'list' if %w[al bl cl sl].include? rating - return nil + if %w[fa fl a ga b c start stub list].include? rating + return rating + elsif rating.eql? 'bplus' + return 'b' + elsif rating.eql? 'a/ga' + return 'a' + elsif %w[al bl cl sl].include? rating + return 'list' + else + return nil + end end def view_count(first_revision, average_views) diff --git a/app/models/campaign.rb b/app/models/campaign.rb index d7a6ef2a70..bd5d147c0d 100644 --- a/app/models/campaign.rb +++ b/app/models/campaign.rb @@ -171,9 +171,10 @@ def valid_start_and_end_dates? def set_slug campaign_slug = slug.presence || title self.slug = campaign_slug.downcase - return if /^[\p{L}0-9_]+$/.match?(campaign_slug.downcase) - # Strip everything but unicode letters and digits, and convert spaces to underscores. - self.slug = campaign_slug.downcase.gsub(/[^\p{L}0-9 ]/, '').tr(' ', '_') + unless /^[\p{L}0-9_]+$/.match?(campaign_slug.downcase) + # Strip everything but unicode letters and digits, and convert spaces to underscores. + self.slug = campaign_slug.downcase.gsub(/[^\p{L}0-9 ]/, '').tr(' ', '_') + end end def set_default_times diff --git a/app/services/add_sandbox_template.rb b/app/services/add_sandbox_template.rb index 7ee90a62ad..e1f181e37b 100644 --- a/app/services/add_sandbox_template.rb +++ b/app/services/add_sandbox_template.rb @@ -19,8 +19,13 @@ def initialize(home_wiki:, sandbox:, sandbox_template:, current_user:) def add_template # Never double-post the sandbox template - return if sandbox_template_present? - default_template_present? ? replace_default_with_sandbox_template : add_sandbox_template + if sandbox_template_present? + return + elsif default_template_present? + replace_default_with_sandbox_template + else + add_sandbox_template + end end def sandbox_template_present? diff --git a/app/services/sandbox_url_updator.rb b/app/services/sandbox_url_updator.rb index a9b2c5bf80..2921a5e883 100644 --- a/app/services/sandbox_url_updator.rb +++ b/app/services/sandbox_url_updator.rb @@ -32,7 +32,7 @@ def validate_new_url raise InvalidUrlError, I18n.t('assignments.invalid_url', url: @new_url) unless new_url_match # Handle mismatched wiki new_language, new_project = new_url_match.captures - unless existing_language == new_language && existing_project == new_project # rubocop:disable Style/GuardClause + unless existing_language == new_language && existing_project == new_project raise MismatchedWikiError, I18n.t('assignments.mismatched_wiki', url: @new_url) end end diff --git a/lib/assignment_manager.rb b/lib/assignment_manager.rb index d999e4c347..313cec6422 100644 --- a/lib/assignment_manager.rb +++ b/lib/assignment_manager.rb @@ -108,7 +108,7 @@ def set_article_from_database def check_wiki_edu_discouraged_article category = Category.find_by(name: ENV['blocked_assignment_category']) - if category.present? && category.article_titles.include?(@clean_title) # rubocop:disable Style/GuardClause + if category.present? && category.article_titles.include?(@clean_title) raise DiscouragedArticleError, I18n.t('assignments.blocked_assignment', title: @clean_title) end end diff --git a/lib/list_course_manager.rb b/lib/list_course_manager.rb index 0208b9de11..e541424eac 100644 --- a/lib/list_course_manager.rb +++ b/lib/list_course_manager.rb @@ -39,11 +39,12 @@ def add_instructor_real_names def add_classroom_program_manager_if_exists cpm = SpecialUsers.classroom_program_manager - return unless cpm && @course.type == 'ClassroomProgramCourse' - CoursesUsers.create(user: cpm, - course: @course, - role: CoursesUsers::Roles::WIKI_ED_STAFF_ROLE, - real_name: cpm.real_name) + if cpm && @course.type == 'ClassroomProgramCourse' + CoursesUsers.create(user: cpm, + course: @course, + role: CoursesUsers::Roles::WIKI_ED_STAFF_ROLE, + real_name: cpm.real_name) + end end def send_approval_notification_emails diff --git a/lib/reference_counter_api.rb b/lib/reference_counter_api.rb index b70d79e44d..cd51cb023b 100644 --- a/lib/reference_counter_api.rb +++ b/lib/reference_counter_api.rb @@ -56,12 +56,15 @@ def get_number_of_references_from_revision_id(rev_id) tries ||= 5 response = toolforge_server.get(references_query_url(rev_id)) parsed_response = Oj.load(response.body) - return { 'num_ref' => parsed_response['num_ref'] } if response.status == 200 - # Log the error and return empty hash - # Sentry.capture_message 'Non-200 response hitting references counter API', level: 'warning', - # extra: { project_code: @project_code, language_code: @language_code, rev_id:, - # status_code: response.status, content: parsed_response } - return { 'num_ref' => nil } + if response.status == 200 + return { 'num_ref' => parsed_response['num_ref'] } + else + # Log the error and return empty hash + # Sentry.capture_message 'Non-200 response hitting references counter API', level: 'warning', + # extra: { project_code: @project_code, language_code: @language_code, rev_id:, + # status_code: response.status, content: parsed_response } + return { 'num_ref' => nil } + end rescue StandardError => e tries -= 1 retry unless tries.zero? diff --git a/lib/revision_feedback_service.rb b/lib/revision_feedback_service.rb index fbba09f3a9..356b426ee1 100644 --- a/lib/revision_feedback_service.rb +++ b/lib/revision_feedback_service.rb @@ -19,8 +19,9 @@ def feedback def citation_feedback ref_tags = @features['feature.wikitext.revision.ref_tags'] # cite_templates = @features['feature.enwiki.revision.cite_templates'] - return unless ref_tags < MINIMUM_REFERENCES - @feedback << 'Cite your sources! This article needs more references.' + if ref_tags < MINIMUM_REFERENCES + @feedback << 'Cite your sources! This article needs more references.' + end end # The largest reasonable average section size, calculated from content characters diff --git a/lib/revision_score_api_handler.rb b/lib/revision_score_api_handler.rb index 8d9a8973d1..5cfc9c757f 100644 --- a/lib/revision_score_api_handler.rb +++ b/lib/revision_score_api_handler.rb @@ -14,8 +14,9 @@ def initialize(language: 'en', project: 'wikipedia', wiki: nil, update_service: # Initialize LiftWingApi if the wiki is valid for it @lift_wing_api = LiftWingApi.new(@wiki, @update_service) if LiftWingApi.valid_wiki?(@wiki) # Initialize ReferenceCounterApi if the wiki is valid for it - return unless ReferenceCounterApi.valid_wiki?(@wiki) - @reference_counter_api = ReferenceCounterApi.new(@wiki, @update_service) + if ReferenceCounterApi.valid_wiki?(@wiki) + @reference_counter_api = ReferenceCounterApi.new(@wiki, @update_service) + end end # Returns data from LiftWing API and/or reference-counter API. diff --git a/lib/training_module_due_date_manager.rb b/lib/training_module_due_date_manager.rb index 178878a316..cba43334dc 100644 --- a/lib/training_module_due_date_manager.rb +++ b/lib/training_module_due_date_manager.rb @@ -49,8 +49,11 @@ def module_progress def flags(course_id) flags_hash = @tmu&.flags - return flags_hash[course_id] || flags_hash if @training_module.exercise? && flags_hash.present? - return flags_hash + if @training_module.exercise? && flags_hash.present? + return flags_hash[course_id] || flags_hash + else + return flags_hash + end end def sandbox_url From aea8df04e2a50432dbbc11e5428b20cd9d3cb5f0 Mon Sep 17 00:00:00 2001 From: Gabina Luz Bianchi Date: Mon, 13 Jan 2025 23:03:27 -0300 Subject: [PATCH 24/25] Revert "added script info in docker docs" This reverts commit c17edb18903ea6955b28e0c76b5e95141c64dc5f. --- docs/docker.md | 7 ------- 1 file changed, 7 deletions(-) diff --git a/docs/docker.md b/docs/docker.md index 67ffabc9fa..1721bcb48c 100644 --- a/docs/docker.md +++ b/docs/docker.md @@ -58,10 +58,3 @@ If you are using Linux you may encounter permission error when trying to change $ sudo chown $USER:$GROUPS -R ./ ``` The command will change the owner of all file inside project directory to the `$USER:$GROUPS` - -If you encounter the following error when connecting to the database: _"There is an issue connecting with your hostname mysql"_, please run the following command: -```sh -bash ./update_hosts.sh -``` -This script automatically resolves the issue by ensuring proper network mapping in your system's ```/etc/hosts``` file, facilitating seamless database connections. It retrieves the IP address of the MySQL Docker container, checks for any existing hostname entries, and updates or removes outdated ones. This process ensures that the hostname ```mysql``` is correctly mapped to the container’s IP address. -This bash script is designed for Linux distributions like Fedora. From a818182e6217c250b5f3de9f1f36bb29ca3de4ea Mon Sep 17 00:00:00 2001 From: Gabina Luz Bianchi Date: Mon, 13 Jan 2025 23:03:27 -0300 Subject: [PATCH 25/25] Revert "added script to update hosts for Database Connection Issue While Setting up using Docker" This reverts commit 3102f3e95a6305d6890a595cb2868759b893fa24. --- update_hosts.sh | 41 ----------------------------------------- 1 file changed, 41 deletions(-) delete mode 100644 update_hosts.sh diff --git a/update_hosts.sh b/update_hosts.sh deleted file mode 100644 index 18cad09897..0000000000 --- a/update_hosts.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash - -# Get the MySQL container ID -MYSQL_CONTAINER_ID=$(docker ps --format '{{.ID}} {{.Names}}' | grep 'wikiedudashboard-mysql-1' | awk '{print $1}') - -echo $MYSQL_CONTAINER_ID - -# Fetch the IP address of the MySQL container -MYSQL_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$MYSQL_CONTAINER_ID") - -# Check if we successfully fetched the IP address -if [ -z "$MYSQL_IP" ]; then - echo "Failed to retrieve the MySQL container IP address. Please ensure the Docker containers are running by executing 'docker compose up -d'." - if grep -q "$MYSQL_IP mysql" /etc/hosts; then - sudo sed -i '/[[:space:]]mysql$/d' /etc/hosts - echo "MySQL entry removed from /etc/hosts." - fi - - exit 1 -fi - -# Print the IP address -echo "MySQL IP address: $MYSQL_IP" - -# Backup /etc/hosts file -sudo cp /etc/hosts /etc/hosts.bak - -# Add MySQL container IP to /etc/hosts -if grep -q "$MYSQL_IP mysql" /etc/hosts; then - echo "MySQL entry already exists in /etc/hosts." - # Remove existing MySQL entry from /etc/hosts (if it exists) - sudo sed -i '/[[:space:]]mysql$/d' /etc/hosts - echo "Removed old MySQL entry from /etc/hosts." -fi - -# Add new MySQL container IP address to /etc/hosts -echo "Adding MySQL container IP address to /etc/hosts" -echo "$MYSQL_IP mysql" | sudo tee -a /etc/hosts > /dev/null - -# Print success message -echo "MySQL IP address has been added to /etc/hosts." \ No newline at end of file