diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..260ff05272 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "nodebb-theme-quickstart"] + path = nodebb-theme-quickstart + url = https://github.com/sschauk/nodebb-theme-quickstart diff --git a/dump.rdb b/dump.rdb new file mode 100644 index 0000000000..ea8ae3adfc Binary files /dev/null and b/dump.rdb differ diff --git a/nodebb-theme-quickstart b/nodebb-theme-quickstart new file mode 160000 index 0000000000..fa9a846bb0 --- /dev/null +++ b/nodebb-theme-quickstart @@ -0,0 +1 @@ +Subproject commit fa9a846bb0469695d2d77932b4abf08aa23c08a0 diff --git a/pidfile 2 b/pidfile 2 new file mode 100644 index 0000000000..950489a781 --- /dev/null +++ b/pidfile 2 @@ -0,0 +1 @@ +28408 \ No newline at end of file diff --git a/pidfile 3 b/pidfile 3 new file mode 100644 index 0000000000..df1cbadf6d --- /dev/null +++ b/pidfile 3 @@ -0,0 +1 @@ +43549 \ No newline at end of file diff --git a/public/scss/global.scss b/public/scss/global.scss index ab7d569242..0cf6c8e8e7 100644 --- a/public/scss/global.scss +++ b/public/scss/global.scss @@ -36,4 +36,4 @@ html[data-dir="rtl"] { h5 { font-size: 1.125rem; } h6 { font-size: 1rem; } } -} \ No newline at end of file +} diff --git a/public/src/admin/extend/widgets.js b/public/src/admin/extend/widgets.js index 1238ee772b..f8805779fc 100644 --- a/public/src/admin/extend/widgets.js +++ b/public/src/admin/extend/widgets.js @@ -253,11 +253,23 @@ define('admin/extend/widgets', [ }); } - function setupCloneButton() { - const clone = $('[component="clone"]'); + function clone(location, template) { + console.log('Dhanya Shah'); + const widgets = $('#active-widgets .tab-pane[data-template="' + template + '"] [data-location="' + location + '"] [data-widget]'); + widgets.each(function () { + const widget = $(this).clone(true); + appendClonedWidget(widget, location); + }); + } + function appendClonedWidget(widget, location) { + $('#active-widgets .active.tab-pane[data-template]:not([data-template="global"]) [data-location="' + location + '"] .widget-area').append(widget); + } + + function setupCloneButton() { // all correct + const cloneContainer = $('[component="clone"]'); const cloneBtn = $('[component="clone/button"]'); - clone.find('.dropdown-menu li').on('click', function () { + cloneContainer.find('.dropdown-menu li').on('click', function () { const template = $(this).find('a').text(); cloneBtn.translateHtml('[[admin/extend/widgets:clone-from]] ' + template + ''); cloneBtn.attr('data-template', template); @@ -281,18 +293,9 @@ define('admin/extend/widgets', [ return currentAreas.indexOf(location) !== -1 ? location : undefined; }).get().filter(function (i) { return i; }); - function clone(location) { - $('#active-widgets .tab-pane[data-template="' + template + '"] [data-location="' + location + '"]').each(function () { - $(this).find('[data-widget]').each(function () { - const widget = $(this).clone(true); - $('#active-widgets .active.tab-pane[data-template]:not([data-template="global"]) [data-location="' + location + '"] .widget-area').append(widget); - }); - }); - } - for (let i = 0, ii = areasToClone.length; i < ii; i++) { const location = areasToClone[i]; - clone(location); + clone(location, template); } alerts.success('[[admin/extend/widgets:alert.clone-success]]'); diff --git a/public/src/admin/manage/categories.js b/public/src/admin/manage/categories.js index 7342d0c1de..65ecc94b56 100644 --- a/public/src/admin/manage/categories.js +++ b/public/src/admin/manage/categories.js @@ -199,50 +199,57 @@ define('admin/manage/categories', [ function itemDidAdd(e) { newCategoryId = e.to.dataset.cid; } - + // asked chatgpt to help find out what function does and give + // suggestions on what a coder can do to reduce cognitive complexity + // this functions updates information once the user finishes drag/drop function itemDragDidEnd(e) { + console.log('Console Logging Saanika Chauk'); const isCategoryUpdate = parseInt(newCategoryId, 10) !== -1; - - // Update needed? - if ((e.newIndex != null && parseInt(e.oldIndex, 10) !== parseInt(e.newIndex, 10)) || isCategoryUpdate) { + if (shouldUpdate(e, isCategoryUpdate)) { const cid = e.item.dataset.cid; - const modified = {}; - // on page 1 baseIndex is 0, on page n baseIndex is (n - 1) * ajaxify.data.categoriesPerPage - // this makes sure order is correct when drag & drop is used on pages > 1 - const baseIndex = (ajaxify.data.pagination.currentPage - 1) * ajaxify.data.categoriesPerPage; - modified[cid] = { - order: baseIndex + e.newIndex + 1, - }; - + const modified = createModObject(e, cid, isCategoryUpdate); if (isCategoryUpdate) { - modified[cid].parentCid = newCategoryId; - - // Show/hide expand buttons after drag completion - const oldParentCid = parseInt(e.from.getAttribute('data-cid'), 10); - const newParentCid = parseInt(e.to.getAttribute('data-cid'), 10); - if (oldParentCid !== newParentCid) { - const toggle = document.querySelector(`.categories li[data-cid="${newParentCid}"] .toggle`); - if (toggle) { - toggle.classList.toggle('invisible', false); - } - - const children = document.querySelectorAll(`.categories li[data-cid="${oldParentCid}"] ul[data-cid] li[data-cid]`); - if (!children.length) { - const toggle = document.querySelector(`.categories li[data-cid="${oldParentCid}"] .toggle`); - if (toggle) { - toggle.classList.toggle('invisible', true); - } - } - - e.item.dataset.parentCid = newParentCid; - } + handleCatUpdate(e); } - newCategoryId = -1; api.put('/categories/' + cid, modified[cid]).catch(alerts.error); } } - + function shouldUpdate(e, isCategoryUpdate) { + return (e.newIndex != null && parseInt(e.oldIndex, 10) !== parseInt(e.newIndex, 10)) || isCategoryUpdate; + } + function createModObject(e, cid, isCategoryUpdate) { + const baseIndex = (ajaxify.data.pagination.currentPage - 1) * ajaxify.data.categoriesPerPage; + const modified = {}; + modified[cid] = { + order: baseIndex + e.newIndex + 1, + }; + if (isCategoryUpdate) { + modified[cid].parentCid = newCategoryId; + } + return modified; + } + function handleCatUpdate(e) { + const oldParentCid = parseInt(e.from.getAttribute('data-cid'), 10); + const newParentCid = parseInt(e.to.getAttribute('data-cid'), 10); + if (oldParentCid !== newParentCid) { + toggleExpand(newParentCid, oldParentCid); + e.item.dataset.parentCid = newParentCid; + } + } + function toggleExpand(newParentCid, oldParentCid) { + const newToggle = document.querySelector(`.categories li[data-cid="${newParentCid}"] .toggle`); + if (newToggle) { + newToggle.classList.toggle('invisible', false); + } + const children = document.querySelectorAll(`.categories li[data-cid="${oldParentCid}"] ul[data-cid] li[data-cid]`); + if (!children.length) { + const oldToggle = document.querySelector(`.categories li[data-cid="${oldParentCid}"] .toggle`); + if (oldToggle) { + oldToggle.classList.toggle('invisible', true); + } + } + } /** * Render categories - recursively * @@ -253,6 +260,7 @@ define('admin/manage/categories', [ */ function renderList(categories, container, parentCategory) { // Translate category names if needed + console.log('rendering categories in list'); let count = 0; const parentId = parentCategory.cid; categories.forEach(function (category, idx, parent) { diff --git a/public/src/client/account/blocks.js b/public/src/client/account/blocks.js index 91b0745a19..7f38e6b28a 100644 --- a/public/src/client/account/blocks.js +++ b/public/src/client/account/blocks.js @@ -9,6 +9,7 @@ define('forum/account/blocks', [ const Blocks = {}; Blocks.init = function () { + console.log('ALANNA CAO'); header.init(); const blockListEl = $('[component="blocks/search/list"]'); const startTypingEl = blockListEl.find('[component="blocks/start-typing"]'); @@ -29,25 +30,7 @@ define('forum/account/blocks', [ searchBy: 'username', paginate: false, }, function (err, data) { - if (err) { - return alerts.error(err); - } - if (!data.users.length) { - noUsersEl.removeClass('hidden'); - return; - } - noUsersEl.addClass('hidden'); - // Only show first 10 matches - if (data.matchCount > 10) { - data.users.length = 10; - } - - app.parseAndTranslate('account/blocks', 'edit', { - edit: data.users, - }, function (html) { - blockListEl.find('[component="blocks/search/match"]').remove(); - html.insertAfter(noUsersEl); - }); + handleUserSearchResponse(err, data, blockListEl, noUsersEl); }); }, 200)); @@ -66,6 +49,28 @@ define('forum/account/blocks', [ }); }; + function handleUserSearchResponse(err, data, blockListEl, noUsersEl) { + if (err) { + return alerts.error(err); + } + if (!data.users.length) { + noUsersEl.removeClass('hidden'); + return; + } + noUsersEl.addClass('hidden'); + // Only show first 10 matches + if (data.matchCount > 10) { + data.users.length = 10; + } + + app.parseAndTranslate('account/blocks', 'edit', { + edit: data.users, + }, function (html) { + blockListEl.find('[component="blocks/search/match"]').remove(); + html.insertAfter(noUsersEl); + }); + } + async function performBlock(uid, action) { return socket.emit('user.toggleBlock', { blockeeUid: uid, diff --git a/public/src/client/account/info.js b/public/src/client/account/info.js index f044860cd6..831961507d 100644 --- a/public/src/client/account/info.js +++ b/public/src/client/account/info.js @@ -10,6 +10,20 @@ define('forum/account/info', ['forum/account/header', 'alerts', 'forum/account/s sessions.prepareSessionRevocation(); }; + function prependModerationNote(html) { + $('[component="account/moderation-note/list"]').prepend(html); + html.find('.timeago').timeago(); + } + + function handleSetModerationNote(noteEl, err, notes) { + console.log('Refactor by Sofian Syed'); + if (err) { + return alerts.error(err); + } + noteEl.val(''); + app.parseAndTranslate('account/info', 'moderationNotes', { moderationNotes: notes }, prependModerationNote); + } + function handleModerationNote() { $('[component="account/save-moderation-note"]').on('click', function () { const noteEl = $('[component="account/moderation-note"]'); @@ -17,17 +31,7 @@ define('forum/account/info', ['forum/account/header', 'alerts', 'forum/account/s socket.emit('user.setModerationNote', { uid: ajaxify.data.uid, note: note, - }, function (err, notes) { - if (err) { - return alerts.error(err); - } - noteEl.val(''); - - app.parseAndTranslate('account/info', 'moderationNotes', { moderationNotes: notes }, function (html) { - $('[component="account/moderation-note/list"]').prepend(html); - html.find('.timeago').timeago(); - }); - }); + }, handleSetModerationNote.bind(null, noteEl)); }); diff --git a/public/src/client/category.js b/public/src/client/category.js index b4f0bb50cb..14dbac8d11 100644 --- a/public/src/client/category.js +++ b/public/src/client/category.js @@ -50,10 +50,73 @@ define('forum/category', [ }, }); + initalizeCategorySearch(); + hooks.fire('action:topics.loaded', { topics: ajaxify.data.topics }); hooks.fire('action:category.loaded', { cid: ajaxify.data.cid }); }; + function initalizeCategorySearch() { + const searchBox = $('#topicSearchInput'); + if (!searchBox.length) { + return; + } + + const searchButton = $('.search-button'); + + // Perform search on input change + searchBox.on('input', function () { + const searchTerm = $(this).val().toLowerCase(); + performTopicSearch(searchTerm); + }); + + // Perform search on enter key press + searchBox.on('keypress', function (e) { + if (e.key === 'Enter') { + const searchTerm = $(this).val().toLowerCase(); + performTopicSearch(searchTerm); + } + }); + + // Perform search when button is clicked + searchButton.on('click', function () { + const searchTerm = searchBox.val().toLowerCase(); + performTopicSearch(searchTerm); + }); + } + + function performTopicSearch(searchTerm) { + const term = searchTerm.toLowerCase(); + + const $topics = $('[component="category/topic"]'); + + // Filter the topics based on the search term + const $matchedTopics = $topics.filter(function () { + const topicText = $(this).find('h3[component="topic/header"]').text().toLowerCase(); // Get the topic text + const metaContent = $(this).find('meta[itemprop="name"]').attr('content') ? + $(this).find('meta[itemprop="name"]').attr('content').toLowerCase() : ''; // Get meta content if it exists + + // True if either topic text or meta content includes search term + return topicText.includes(term) || metaContent.includes(term); + }); + + // Show matched topics and hide others + $topics.addClass('hidden'); + $matchedTopics.removeClass('hidden'); + + // Handle case where no topics match the search term + if ($matchedTopics.length === 0) { + if ($('[component="category/topic/no-matches"]').length === 0) { + $(`
No topics match the search term "${searchTerm}".
`) + .insertAfter('[component="category/topic"]:last'); + } else { + $('[component="category/topic/no-matches"]').removeClass('hidden'); + } + } else { + $('[component="category/topic/no-matches"]').addClass('hidden'); + } + } + function handleScrollToTopicIndex() { let topicIndex = ajaxify.data.topicIndex; if (topicIndex && utils.isNumber(topicIndex)) { diff --git a/public/src/client/topic/threadTools.js b/public/src/client/topic/threadTools.js index a66b293a73..7ec13770ab 100644 --- a/public/src/client/topic/threadTools.js +++ b/public/src/client/topic/threadTools.js @@ -146,6 +146,13 @@ define('forum/topic/threadTools', [ changeWatching('ignore'); }); + // CHATGPT SUGGESTED CODE TESTING AQUI + // require(['pinButton'], function (PinButton) { + // PinButton.init(function () { + // console.log('Button state changed'); + // }); + // }); + function changeWatching(type, state = 1) { const method = state ? 'put' : 'del'; api[method](`/topics/${tid}/${type}`, {}, () => { diff --git a/src/controllers/mods.js b/src/controllers/mods.js index 4976dd9e82..05a4178160 100644 --- a/src/controllers/mods.js +++ b/src/controllers/mods.js @@ -18,6 +18,27 @@ const helpers = require('./helpers'); const modsController = module.exports; modsController.flags = {}; +function adminModCid(isAdminOrGlobalMod, moderatedCidsLength) { + return (!isAdminOrGlobalMod && moderatedCidsLength); +} + +function filtersCidInitialize(filters, res) { + if (!filters.cid) { + // If mod and no cid filter, add filter for their modded categories + return res.locals.cids; + } else if (Array.isArray(filters.cid)) { + // Remove cids they do not moderate + return filters.cid.filter(cid => res.locals.cids.includes(String(cid))); + } else if (!res.locals.cids.includes(String(filters.cid))) { + return res.locals.cids; + } +} + +function paginationFilterCheck(filters) { + return (Object.keys(filters).length === 1 && filters.hasOwnProperty('page')) || + (Object.keys(filters).length === 2 && filters.hasOwnProperty('page') && filters.hasOwnProperty('perPage')); +} + modsController.flags.list = async function (req, res) { const validFilters = ['assignee', 'state', 'reporterId', 'type', 'targetUid', 'cid', 'quick', 'page', 'perPage']; const validSorts = ['newest', 'oldest', 'reports', 'upvotes', 'downvotes', 'replies']; @@ -31,13 +52,22 @@ modsController.flags.list = async function (req, res) { const [isAdminOrGlobalMod, moderatedCids,, { sorts }] = results; let [,, { filters }] = results; - if (!(isAdminOrGlobalMod || !!moderatedCids.length)) { + const AdminModeratedCidVal = adminModCid(isAdminOrGlobalMod, moderatedCids.length); + if ((!(isAdminOrGlobalMod || !!moderatedCids.length))) { + console.log('KAREN GONZALEZ'); return helpers.notAllowed(req, res); } - if (!isAdminOrGlobalMod && moderatedCids.length) { + if (AdminModeratedCidVal) { res.locals.cids = moderatedCids.map(cid => String(cid)); } + // if (!(isAdminOrGlobalMod || !!moderatedCids.length)) { + // return helpers.notAllowed(req, res); + // } + + // if (!isAdminOrGlobalMod && moderatedCids.length) { + // res.locals.cids = moderatedCids.map(cid => String(cid)); + // } // Parse query string params for filters, eliminate non-valid filters filters = filters.reduce((memo, cur) => { @@ -54,24 +84,34 @@ modsController.flags.list = async function (req, res) { let hasFilter = !!Object.keys(filters).length; + // if (res.locals.cids) { + // if (!filters.cid) { + // If mod and no cid filter, add filter for their modded categories + // filters.cid = res.locals.cids; + // } else if (Array.isArray(filters.cid)) { + // // Remove cids they do not moderate + // filters.cid = filters.cid.filter(cid => res.locals.cids.includes(String(cid))); + // } else if (!res.locals.cids.includes(String(filters.cid))) { + // filters.cid = res.locals.cids; + // hasFilter = false; + // } + // } if (res.locals.cids) { - if (!filters.cid) { - // If mod and no cid filter, add filter for their modded categories - filters.cid = res.locals.cids; - } else if (Array.isArray(filters.cid)) { - // Remove cids they do not moderate - filters.cid = filters.cid.filter(cid => res.locals.cids.includes(String(cid))); - } else if (!res.locals.cids.includes(String(filters.cid))) { - filters.cid = res.locals.cids; + filters.cid = filtersCidInitialize(filters, res); + if (!res.locals.cids.includes(String(filters.cid))) { hasFilter = false; } } + console.log('KAREN GONZALEZ'); // Pagination doesn't count as a filter - if ( - (Object.keys(filters).length === 1 && filters.hasOwnProperty('page')) || - (Object.keys(filters).length === 2 && filters.hasOwnProperty('page') && filters.hasOwnProperty('perPage')) - ) { + // if ( + // (Object.keys(filters).length === 1 && filters.hasOwnProperty('page')) || + // (Object.keys(filters).length === 2 && filters.hasOwnProperty('page') && filters.hasOwnProperty('perPage')) + // ) { + // hasFilter = false; + // } + if (paginationFilterCheck(filters)) { hasFilter = false; } diff --git a/src/views/partials/data/topic.tpl b/src/views/partials/data/topic.tpl index 846d17eb40..6b78529dab 100644 --- a/src/views/partials/data/topic.tpl +++ b/src/views/partials/data/topic.tpl @@ -1 +1,3 @@ -data-index="{posts.index}" data-pid="{posts.pid}" data-uid="{posts.uid}" data-timestamp="{posts.timestamp}" data-username="{posts.user.username}" data-userslug="{posts.user.userslug}"{{{ if posts.allowDupe }}} data-allow-dupe="1"{{{ end }}}{{{ if posts.navigatorIgnore }}} data-navigator-ignore="1"{{{ end }}} itemprop="comment" itemtype="http://schema.org/Comment" itemscope \ No newline at end of file +data-index="{posts.index}" data-pid="{posts.pid}" data-uid="{posts.uid}" data-timestamp="{posts.timestamp}" data-username="{posts.user.username}" data-userslug="{posts.user.userslug}"{{{ if posts.allowDupe }}} data-allow-dupe="1"{{{ end }}}{{{ if posts.navigatorIgnore }}} data-navigator-ignore="1"{{{ end }}} itemprop="comment" itemtype="http://schema.org/Comment" itemscope + +