From c0ddf55b48a1348bb88337d70684c81d7732b94e Mon Sep 17 00:00:00 2001 From: Liam Date: Tue, 28 May 2024 22:54:45 -0400 Subject: [PATCH 01/35] Add lex stage with intermediate result generation --- assets/js/booru.js | 2 +- assets/js/match_query.ts | 8 +-- assets/js/query/__tests__/lex.spec.ts | 4 +- assets/js/query/lex.ts | 74 +++++++++++++++++++-------- assets/js/query/parse.ts | 8 +-- assets/js/utils/__tests__/tag.spec.ts | 2 +- 6 files changed, 68 insertions(+), 30 deletions(-) diff --git a/assets/js/booru.js b/assets/js/booru.js index 03d0dff8..1f963dbe 100644 --- a/assets/js/booru.js +++ b/assets/js/booru.js @@ -1,5 +1,5 @@ import { $ } from './utils/dom'; -import parseSearch from './match_query'; +import { parseSearch } from './match_query'; import store from './utils/store'; /** diff --git a/assets/js/match_query.ts b/assets/js/match_query.ts index 5ddafea3..d6142b94 100644 --- a/assets/js/match_query.ts +++ b/assets/js/match_query.ts @@ -1,5 +1,5 @@ import { defaultMatcher } from './query/matcher'; -import { generateLexArray } from './query/lex'; +import { generateLexArray, generateLexResult } from './query/lex'; import { parseTokens } from './query/parse'; import { getAstMatcherForTerm } from './query/term'; @@ -7,9 +7,11 @@ function parseWithDefaultMatcher(term: string, fuzz: number) { return getAstMatcherForTerm(term, fuzz, defaultMatcher); } -function parseSearch(query: string) { +export function parseSearch(query: string) { const tokens = generateLexArray(query, parseWithDefaultMatcher); return parseTokens(tokens); } -export default parseSearch; +export function getTermContexts(query: string) { + return generateLexResult(query, parseWithDefaultMatcher).termContexts; +} diff --git a/assets/js/query/__tests__/lex.spec.ts b/assets/js/query/__tests__/lex.spec.ts index 427f4dfb..19516a4a 100644 --- a/assets/js/query/__tests__/lex.spec.ts +++ b/assets/js/query/__tests__/lex.spec.ts @@ -170,8 +170,8 @@ describe('Lexical analysis', () => { expect(array).toEqual([noMatch, noMatch, 'or_op', noMatch, 'or_op', noMatch, 'or_op']); }); - it('should throw exception on mismatched parentheses', () => { + it('should mark error on mismatched parentheses', () => { expect(() => generateLexArray('(safe OR solo AND fluttershy', parseTerm)).toThrow('Mismatched parentheses.'); - // expect(() => generateLexArray(')bad', parseTerm)).toThrow('Mismatched parentheses.'); + // expect(() => generateLexArray(')bad', parseTerm).error).toThrow('Mismatched parentheses.'); }); }); diff --git a/assets/js/query/lex.ts b/assets/js/query/lex.ts index d234b1c8..2c950bd1 100644 --- a/assets/js/query/lex.ts +++ b/assets/js/query/lex.ts @@ -22,10 +22,18 @@ const tokenList: Token[] = [ export type ParseTerm = (term: string, fuzz: number, boost: number) => AstMatcher; -export function generateLexArray(searchStr: string, parseTerm: ParseTerm): TokenList { +export type Range = [number, number]; +export type TermContext = [Range, string]; + +export interface LexResult { + tokenList: TokenList, + termContexts: TermContext[], + error: ParseError | null +} + +export function generateLexResult(searchStr: string, parseTerm: ParseTerm): LexResult { const opQueue: string[] = [], - groupNegate: boolean[] = [], - tokenStack: TokenList = []; + groupNegate: boolean[] = []; let searchTerm: string | null = null; let boostFuzzStr = ''; @@ -35,10 +43,25 @@ export function generateLexArray(searchStr: string, parseTerm: ParseTerm): Token let fuzz = 0; let lparenCtr = 0; - const pushTerm = () => { + let termIndex = 0; + let index = 0; + + const ret: LexResult = { + tokenList: [], + termContexts: [], + error: null + }; + + const beginTerm = (token: string) => { + searchTerm = token; + termIndex = index; + }; + + const endTerm = () => { if (searchTerm !== null) { // Push to stack. - tokenStack.push(parseTerm(searchTerm, fuzz, boost)); + ret.tokenList.push(parseTerm(searchTerm, fuzz, boost)); + ret.termContexts.push([[termIndex, termIndex + searchTerm.length], searchTerm]); // Reset term and options data. boost = 1; fuzz = 0; @@ -48,7 +71,7 @@ export function generateLexArray(searchStr: string, parseTerm: ParseTerm): Token } if (negate) { - tokenStack.push('not_op'); + ret.tokenList.push('not_op'); negate = false; } }; @@ -64,19 +87,19 @@ export function generateLexArray(searchStr: string, parseTerm: ParseTerm): Token const token = match[0]; if (searchTerm !== null && (['and_op', 'or_op'].indexOf(tokenName) !== -1 || tokenName === 'rparen' && lparenCtr === 0)) { - pushTerm(); + endTerm(); } switch (tokenName) { case 'and_op': while (opQueue[0] === 'and_op') { - tokenStack.push(assertNotUndefined(opQueue.shift())); + ret.tokenList.push(assertNotUndefined(opQueue.shift())); } opQueue.unshift('and_op'); break; case 'or_op': while (opQueue[0] === 'and_op' || opQueue[0] === 'or_op') { - tokenStack.push(assertNotUndefined(opQueue.shift())); + ret.tokenList.push(assertNotUndefined(opQueue.shift())); } opQueue.unshift('or_op'); break; @@ -113,10 +136,10 @@ export function generateLexArray(searchStr: string, parseTerm: ParseTerm): Token if (op === 'lparen') { break; } - tokenStack.push(op); + ret.tokenList.push(op); } if (groupNegate.length > 0 && groupNegate.pop()) { - tokenStack.push('not_op'); + ret.tokenList.push('not_op'); } } break; @@ -128,7 +151,7 @@ export function generateLexArray(searchStr: string, parseTerm: ParseTerm): Token boostFuzzStr += token; } else { - searchTerm = token; + beginTerm(token); } break; case 'boost': @@ -137,7 +160,7 @@ export function generateLexArray(searchStr: string, parseTerm: ParseTerm): Token boostFuzzStr += token; } else { - searchTerm = token; + beginTerm(token); } break; case 'quoted_lit': @@ -145,7 +168,7 @@ export function generateLexArray(searchStr: string, parseTerm: ParseTerm): Token searchTerm += token; } else { - searchTerm = token; + beginTerm(token); } break; case 'word': @@ -159,7 +182,7 @@ export function generateLexArray(searchStr: string, parseTerm: ParseTerm): Token searchTerm += token; } else { - searchTerm = token; + beginTerm(token); } break; default: @@ -171,6 +194,7 @@ export function generateLexArray(searchStr: string, parseTerm: ParseTerm): Token // Truncate string and restart the token tests. localSearchStr = localSearchStr.substring(token.length); + index += token.length; // Break since we have found a match. break; @@ -178,14 +202,24 @@ export function generateLexArray(searchStr: string, parseTerm: ParseTerm): Token } // Append final tokens to the stack. - pushTerm(); + endTerm(); if (opQueue.indexOf('rparen') !== -1 || opQueue.indexOf('lparen') !== -1) { - throw new ParseError('Mismatched parentheses.'); + ret.error = new ParseError('Mismatched parentheses.'); } - // Concatenatte remaining operators to the token stack. - tokenStack.push(...opQueue); + // Concatenate remaining operators to the token stack. + ret.tokenList.push(...opQueue); - return tokenStack; + return ret; +} + +export function generateLexArray(searchStr: string, parseTerm: ParseTerm): TokenList { + const ret = generateLexResult(searchStr, parseTerm); + + if (ret.error) { + throw ret.error; + } + + return ret.tokenList; } diff --git a/assets/js/query/parse.ts b/assets/js/query/parse.ts index f5a09fcc..fea7659b 100644 --- a/assets/js/query/parse.ts +++ b/assets/js/query/parse.ts @@ -4,9 +4,11 @@ import { AstMatcher, ParseError, TokenList } from './types'; export function parseTokens(lexicalArray: TokenList): AstMatcher { const operandStack: AstMatcher[] = []; - lexicalArray.forEach((token, i) => { + for (let i = 0; i < lexicalArray.length; i += 1) { + const token = lexicalArray[i]; + if (token === 'not_op') { - return; + continue; } let intermediate: AstMatcher; @@ -36,7 +38,7 @@ export function parseTokens(lexicalArray: TokenList): AstMatcher { else { operandStack.push(intermediate); } - }); + } if (operandStack.length > 1) { throw new ParseError('Missing operator.'); diff --git a/assets/js/utils/__tests__/tag.spec.ts b/assets/js/utils/__tests__/tag.spec.ts index 44bc565f..61a196b8 100644 --- a/assets/js/utils/__tests__/tag.spec.ts +++ b/assets/js/utils/__tests__/tag.spec.ts @@ -1,7 +1,7 @@ import { displayTags, getHiddenTags, getSpoileredTags, imageHitsComplex, imageHitsTags, TagData } from '../tag'; import { mockStorage } from '../../../test/mock-storage'; import { getRandomArrayItem } from '../../../test/randomness'; -import parseSearch from '../../match_query'; +import { parseSearch } from '../../match_query'; import { SpoilerType } from '../../../types/booru-object'; describe('Tag utilities', () => { From 8c988b002ded94b64a11aa9ca84027973194f0cd Mon Sep 17 00:00:00 2001 From: KoloMl Date: Wed, 29 May 2024 23:57:36 +0400 Subject: [PATCH 02/35] Support search field autocompletion, enabled autocomplete for header --- assets/js/autocomplete.js | 71 +++++++++++++++++-- .../templates/layout/_header.html.slime | 2 +- 2 files changed, 67 insertions(+), 6 deletions(-) diff --git a/assets/js/autocomplete.js b/assets/js/autocomplete.js index 1844dda5..4d15b860 100644 --- a/assets/js/autocomplete.js +++ b/assets/js/autocomplete.js @@ -4,9 +4,19 @@ import { LocalAutocompleter } from './utils/local-autocompleter'; import { handleError } from './utils/requests'; +import { getTermContexts } from "./match_query"; const cache = {}; -let inputField, originalTerm; +/** @type {HTMLInputElement} */ +let inputField, + /** @type {string} */ + originalTerm, + /** @type {string} */ + originalQuery, + /** @type {TermContext[]} */ + searchTokens, + /** @type {TermContext} */ + selectedTerm; function removeParent() { const parent = document.querySelector('.autocomplete'); @@ -18,13 +28,37 @@ function removeSelected() { if (selected) selected.classList.remove('autocomplete__item--selected'); } +function isSearchField() { + return inputField && inputField.name === 'q'; +} + +function restoreOriginalValue() { + inputField.value = isSearchField() ? originalQuery : originalTerm; +} + +function applySelectedValue(selection) { + if (!isSearchField()) { + inputField.value = selection; + return; + } + + if (!selectedTerm) { + return; + } + + const [startIndex, endIndex] = selectedTerm[0]; + inputField.value = originalQuery.slice(0, startIndex) + selection + originalQuery.slice(endIndex); + inputField.setSelectionRange(startIndex + selection.length, startIndex + selection.length); + inputField.focus(); +} + function changeSelected(firstOrLast, current, sibling) { if (current && sibling) { // if the currently selected item has a sibling, move selection to it current.classList.remove('autocomplete__item--selected'); sibling.classList.add('autocomplete__item--selected'); } else if (current) { // if the next keypress will take the user outside the list, restore the unautocompleted term - inputField.value = originalTerm; + restoreOriginalValue(); removeSelected(); } else if (firstOrLast) { // if no item in the list is selected, select the first or last @@ -37,12 +71,15 @@ function keydownHandler(event) { firstItem = document.querySelector('.autocomplete__item:first-of-type'), lastItem = document.querySelector('.autocomplete__item:last-of-type'); + // Prevent submission of the search field when Enter was hit + if (event.keyCode === 13 && isSearchField() && selected) event.preventDefault(); // Enter + if (event.keyCode === 38) changeSelected(lastItem, selected, selected && selected.previousSibling); // ArrowUp if (event.keyCode === 40) changeSelected(firstItem, selected, selected && selected.nextSibling); // ArrowDown if (event.keyCode === 13 || event.keyCode === 27 || event.keyCode === 188) removeParent(); // Enter || Esc || Comma if (event.keyCode === 38 || event.keyCode === 40) { // ArrowUp || ArrowDown const newSelected = document.querySelector('.autocomplete__item--selected'); - if (newSelected) inputField.value = newSelected.dataset.value; + if (newSelected) applySelectedValue(newSelected.dataset.value); event.preventDefault(); } } @@ -64,7 +101,7 @@ function createItem(list, suggestion) { }); item.addEventListener('click', () => { - inputField.value = item.dataset.value; + applySelectedValue(item.dataset.value); inputField.dispatchEvent( new CustomEvent('autocomplete', { detail: { @@ -122,6 +159,17 @@ function getSuggestions(term) { return fetch(`${inputField.dataset.acSource}${term}`).then(response => response.json()); } +function getSelectedTerm() { + if (!inputField || !originalQuery) { + return null; + } + + const selectionIndex = Math.min(inputField.selectionStart, inputField.selectionEnd); + const terms = getTermContexts(originalQuery); + + return terms.find(([range]) => range[0] < selectionIndex && range[1] >= selectionIndex); +} + function listenAutocomplete() { let timeout; @@ -138,7 +186,20 @@ function listenAutocomplete() { if (localAc !== null && 'ac' in event.target.dataset) { inputField = event.target; - originalTerm = `${inputField.value}`.toLowerCase(); + + if (isSearchField()) { + originalQuery = inputField.value; + selectedTerm = getSelectedTerm(); + + // We don't need to run auto-completion if user is not selecting tag at all + if (!selectedTerm) { + return; + } + + originalTerm = selectedTerm[1]; + } else { + originalTerm = `${inputField.value}`.toLowerCase(); + } const suggestions = localAc.topK(originalTerm, 5).map(({ name, imageCount }) => ({ label: `${name} (${imageCount})`, value: name })); diff --git a/lib/philomena_web/templates/layout/_header.html.slime b/lib/philomena_web/templates/layout/_header.html.slime index 23935c9c..ea268bf3 100644 --- a/lib/philomena_web/templates/layout/_header.html.slime +++ b/lib/philomena_web/templates/layout/_header.html.slime @@ -12,7 +12,7 @@ header.header i.fa.fa-upload = form_for @conn, Routes.search_path(@conn, :index), [method: "get", class: "header__search flex flex--no-wrap flex--centered", enforce_utf8: false], fn f -> - input.input.header__input.header__input--search#q name="q" title="For terms all required, separate with ',' or 'AND'; also supports 'OR' for optional terms and '-' or 'NOT' for negation. Search with a blank query for more options or click the ? for syntax help." value=@conn.params["q"] placeholder="Search" autocapitalize="none" + input.input.header__input.header__input--search#q name="q" title="For terms all required, separate with ',' or 'AND'; also supports 'OR' for optional terms and '-' or 'NOT' for negation. Search with a blank query for more options or click the ? for syntax help." value=@conn.params["q"] placeholder="Search" autocapitalize="none" autocomplete="off" data-ac="true" data-ac-min-length="3" data-ac-source="/autocomplete/tags?term=" = if present?(@conn.params["sf"]) do input type="hidden" name="sf" value=@conn.params["sf"] From f31fcf86b363eb0bf51dcd7e446bd829ca10751f Mon Sep 17 00:00:00 2001 From: KoloMl Date: Thu, 30 May 2024 00:32:03 +0400 Subject: [PATCH 03/35] Close the autocomplete window once user moved outside current term --- assets/js/autocomplete.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/assets/js/autocomplete.js b/assets/js/autocomplete.js index 4d15b860..4a6862ef 100644 --- a/assets/js/autocomplete.js +++ b/assets/js/autocomplete.js @@ -71,8 +71,20 @@ function keydownHandler(event) { firstItem = document.querySelector('.autocomplete__item:first-of-type'), lastItem = document.querySelector('.autocomplete__item:last-of-type'); - // Prevent submission of the search field when Enter was hit - if (event.keyCode === 13 && isSearchField() && selected) event.preventDefault(); // Enter + if (isSearchField()) { + // Prevent submission of the search field when Enter was hit + if (selected && event.keyCode === 13) event.preventDefault(); // Enter + + // Close autocompletion popup when text cursor is outside current tag + if (selectedTerm && firstItem && (event.keyCode === 37 || event.keyCode === 39)) { // ArrowLeft || ArrowRight + requestAnimationFrame(() => { + const selectionIndex = Math.min(inputField.selectionStart, inputField.selectionEnd); + const [startIndex, endIndex] = selectedTerm[0]; + + if (startIndex > selectionIndex || endIndex < selectionIndex) removeParent(); + }) + } + } if (event.keyCode === 38) changeSelected(lastItem, selected, selected && selected.previousSibling); // ArrowUp if (event.keyCode === 40) changeSelected(firstItem, selected, selected && selected.nextSibling); // ArrowDown From f1aec2fd581ddd8f26ee3c4d85c0e6057fa5122f Mon Sep 17 00:00:00 2001 From: KoloMl Date: Thu, 30 May 2024 01:37:35 +0400 Subject: [PATCH 04/35] Close autocomplete window when selection moved outside active term by click --- assets/js/autocomplete.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/assets/js/autocomplete.js b/assets/js/autocomplete.js index 4a6862ef..392af624 100644 --- a/assets/js/autocomplete.js +++ b/assets/js/autocomplete.js @@ -66,6 +66,13 @@ function changeSelected(firstOrLast, current, sibling) { } } +function isSelectionOutsideCurrentTerm() { + const selectionIndex = Math.min(inputField.selectionStart, inputField.selectionEnd); + const [startIndex, endIndex] = selectedTerm[0]; + + return startIndex > selectionIndex || endIndex < selectionIndex; +} + function keydownHandler(event) { const selected = document.querySelector('.autocomplete__item--selected'), firstItem = document.querySelector('.autocomplete__item:first-of-type'), @@ -78,10 +85,7 @@ function keydownHandler(event) { // Close autocompletion popup when text cursor is outside current tag if (selectedTerm && firstItem && (event.keyCode === 37 || event.keyCode === 39)) { // ArrowLeft || ArrowRight requestAnimationFrame(() => { - const selectionIndex = Math.min(inputField.selectionStart, inputField.selectionEnd); - const [startIndex, endIndex] = selectedTerm[0]; - - if (startIndex > selectionIndex || endIndex < selectionIndex) removeParent(); + if (isSelectionOutsideCurrentTerm()) removeParent(); }) } } @@ -247,6 +251,7 @@ function listenAutocomplete() { // If there's a click outside the inputField, remove autocomplete document.addEventListener('click', event => { if (event.target && event.target !== inputField) removeParent(); + if (event.target === inputField && isSearchField() && isSelectionOutsideCurrentTerm()) removeParent(); }); function fetchLocalAutocomplete(event) { From 3f2e887aec215c28085fa57547840ef4b4a4c7f4 Mon Sep 17 00:00:00 2001 From: KoloMl Date: Thu, 30 May 2024 21:55:41 +0400 Subject: [PATCH 05/35] Fixed issues marked by linter --- assets/js/autocomplete.js | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/assets/js/autocomplete.js b/assets/js/autocomplete.js index 392af624..9ac4c2b8 100644 --- a/assets/js/autocomplete.js +++ b/assets/js/autocomplete.js @@ -4,19 +4,17 @@ import { LocalAutocompleter } from './utils/local-autocompleter'; import { handleError } from './utils/requests'; -import { getTermContexts } from "./match_query"; +import { getTermContexts } from './match_query'; const cache = {}; /** @type {HTMLInputElement} */ let inputField, - /** @type {string} */ - originalTerm, - /** @type {string} */ - originalQuery, - /** @type {TermContext[]} */ - searchTokens, - /** @type {TermContext} */ - selectedTerm; + /** @type {string} */ + originalTerm, + /** @type {string} */ + originalQuery, + /** @type {TermContext} */ + selectedTerm; function removeParent() { const parent = document.querySelector('.autocomplete'); @@ -86,7 +84,7 @@ function keydownHandler(event) { if (selectedTerm && firstItem && (event.keyCode === 37 || event.keyCode === 39)) { // ArrowLeft || ArrowRight requestAnimationFrame(() => { if (isSelectionOutsideCurrentTerm()) removeParent(); - }) + }); } } @@ -213,7 +211,8 @@ function listenAutocomplete() { } originalTerm = selectedTerm[1]; - } else { + } + else { originalTerm = `${inputField.value}`.toLowerCase(); } From e84d451c2b6b3d9c3ed33d9ffa999e08566a5338 Mon Sep 17 00:00:00 2001 From: Liam Date: Sun, 28 Apr 2024 20:55:27 -0400 Subject: [PATCH 06/35] mix convert_to_verified_routes && mix format --- .../admin/advert/image_controller.ex | 2 +- .../controllers/admin/advert_controller.ex | 6 +-- .../admin/artist_link/contact_controller.ex | 4 +- .../admin/artist_link/reject_controller.ex | 4 +- .../artist_link/verification_controller.ex | 4 +- .../admin/badge/image_controller.ex | 2 +- .../controllers/admin/badge_controller.ex | 4 +- .../controllers/admin/batch/tag_controller.ex | 2 +- .../admin/dnp_entry/transition_controller.ex | 4 +- .../controllers/admin/donation_controller.ex | 4 +- .../admin/fingerprint_ban_controller.ex | 8 +-- .../controllers/admin/forum_controller.ex | 4 +- .../controllers/admin/mod_note_controller.ex | 6 +-- .../admin/report/claim_controller.ex | 6 +-- .../admin/report/close_controller.ex | 2 +- .../admin/site_notice_controller.ex | 6 +-- .../admin/subnet_ban_controller.ex | 8 +-- .../admin/user/activation_controller.ex | 4 +- .../admin/user/api_key_controller.ex | 2 +- .../admin/user/avatar_controller.ex | 2 +- .../admin/user/downvote_controller.ex | 2 +- .../admin/user/force_filter_controller.ex | 4 +- .../admin/user/unlock_controller.ex | 2 +- .../admin/user/verification_controller.ex | 6 +-- .../controllers/admin/user/vote_controller.ex | 2 +- .../controllers/admin/user/wipe_controller.ex | 2 +- .../controllers/admin/user_ban_controller.ex | 8 +-- .../controllers/admin/user_controller.ex | 4 +- .../controllers/avatar_controller.ex | 4 +- .../controllers/channel/nsfw_controller.ex | 4 +- .../controllers/channel_controller.ex | 6 +-- .../controllers/confirmation_controller.ex | 2 +- .../conversation/hide_controller.ex | 4 +- .../conversation/message_controller.ex | 4 +- .../conversation/read_controller.ex | 4 +- .../conversation/report_controller.ex | 4 +- .../controllers/conversation_controller.ex | 2 +- .../controllers/dnp_entry_controller.ex | 4 +- .../duplicate_report/accept_controller.ex | 6 +-- .../accept_reverse_controller.ex | 6 +-- .../duplicate_report/claim_controller.ex | 6 +-- .../duplicate_report/reject_controller.ex | 4 +- .../duplicate_report_controller.ex | 4 +- .../controllers/filter/clear_recent.ex | 2 +- .../controllers/filter/public_controller.ex | 4 +- .../controllers/filter_controller.ex | 8 +-- .../controllers/gallery/report_controller.ex | 4 +- .../controllers/gallery_controller.ex | 6 +-- .../controllers/image/anonymous_controller.ex | 4 +- .../controllers/image/approve_controller.ex | 4 +- .../image/comment/approve_controller.ex | 4 +- .../image/comment/delete_controller.ex | 10 ++-- .../image/comment/hide_controller.ex | 18 ++----- .../image/comment/report_controller.ex | 4 +- .../controllers/image/comment_controller.ex | 8 ++- .../image/comment_lock_controller.ex | 6 +-- .../controllers/image/delete_controller.ex | 14 +++--- .../image/description_lock_controller.ex | 6 +-- .../controllers/image/destroy_controller.ex | 8 +-- .../controllers/image/feature_controller.ex | 6 +-- .../controllers/image/file_controller.ex | 6 +-- .../controllers/image/hash_controller.ex | 4 +- .../controllers/image/navigate_controller.ex | 6 +-- .../controllers/image/random_controller.ex | 4 +- .../controllers/image/repair_controller.ex | 4 +- .../controllers/image/report_controller.ex | 4 +- .../image/scratchpad_controller.ex | 4 +- .../image/source_history_controller.ex | 4 +- .../image/tag_change_controller.ex | 4 +- .../controllers/image/tag_lock_controller.ex | 8 +-- .../controllers/image/tamper_controller.ex | 4 +- .../controllers/image_controller.ex | 4 +- .../controllers/page_controller.ex | 4 +- .../controllers/password_controller.ex | 4 +- .../profile/artist_link_controller.ex | 8 +-- .../controllers/profile/award_controller.ex | 6 +-- .../profile/commission/item_controller.ex | 6 +-- .../profile/commission/report_controller.ex | 4 +- .../profile/commission_controller.ex | 8 +-- .../profile/description_controller.ex | 2 +- .../controllers/profile/report_controller.ex | 4 +- .../profile/scratchpad_controller.ex | 2 +- .../registration/email_controller.ex | 10 ++-- .../registration/name_controller.ex | 2 +- .../registration/password_controller.ex | 4 +- .../registration/totp_controller.ex | 4 +- .../controllers/registration_controller.ex | 2 +- .../controllers/report_controller.ex | 2 +- .../controllers/session_controller.ex | 2 +- .../controllers/setting_controller.ex | 2 +- .../controllers/tag/alias_controller.ex | 4 +- .../controllers/tag/image_controller.ex | 6 +-- .../controllers/tag/reindex_controller.ex | 2 +- .../controllers/tag_controller.ex | 6 +-- .../controllers/topic/hide_controller.ex | 10 ++-- .../controllers/topic/lock_controller.ex | 10 ++-- .../controllers/topic/move_controller.ex | 6 +-- .../controllers/topic/poll/vote_controller.ex | 8 +-- .../controllers/topic/poll_controller.ex | 4 +- .../topic/post/approve_controller.ex | 6 +-- .../topic/post/delete_controller.ex | 6 +-- .../controllers/topic/post/hide_controller.ex | 10 ++-- .../topic/post/report_controller.ex | 4 +- .../controllers/topic/post_controller.ex | 6 +-- .../controllers/topic/stick_controller.ex | 10 ++-- .../controllers/topic_controller.ex | 10 ++-- .../controllers/unlock_controller.ex | 2 +- lib/philomena_web/plugs/map_parameter_plug.ex | 2 +- lib/philomena_web/plugs/tor_plug.ex | 2 +- lib/philomena_web/plugs/totp_plug.ex | 2 +- .../activity/_channel_strip.html.slime | 2 +- .../activity/_topic_strip.html.slime | 6 +-- .../templates/activity/index.html.slime | 2 +- .../templates/admin/advert/_form.html.slime | 2 +- .../templates/admin/advert/edit.html.slime | 2 +- .../admin/advert/image/edit.html.slime | 2 +- .../templates/admin/advert/index.html.slime | 8 +-- .../templates/admin/advert/new.html.slime | 2 +- .../admin/approval/_approvals.html.slime | 8 +-- .../templates/admin/approval/index.html.slime | 2 +- .../admin/artist_link/index.html.slime | 18 +++---- .../templates/admin/badge/_form.html.slime | 2 +- .../templates/admin/badge/edit.html.slime | 4 +- .../admin/badge/image/edit.html.slime | 2 +- .../templates/admin/badge/index.html.slime | 8 +-- .../templates/admin/badge/new.html.slime | 4 +- .../admin/badge/user/index.html.slime | 4 +- .../admin/dnp_entry/index.html.slime | 36 ++++++------- .../admin/donation/_table.html.slime | 2 +- .../templates/admin/donation/index.html.slime | 2 +- .../admin/donation/user/index.html.slime | 2 +- .../admin/fingerprint_ban/edit.html.slime | 4 +- .../admin/fingerprint_ban/index.html.slime | 12 ++--- .../admin/fingerprint_ban/new.html.slime | 4 +- .../templates/admin/forum/edit.html.slime | 4 +- .../templates/admin/forum/index.html.slime | 6 +-- .../templates/admin/forum/new.html.slime | 4 +- .../admin/mod_note/_table.html.slime | 6 +-- .../templates/admin/mod_note/edit.html.slime | 2 +- .../templates/admin/mod_note/index.html.slime | 2 +- .../templates/admin/mod_note/new.html.slime | 2 +- .../admin/report/_reports.html.slime | 12 ++--- .../templates/admin/report/index.html.slime | 4 +- .../templates/admin/report/show.html.slime | 12 ++--- .../admin/site_notice/edit.html.slime | 2 +- .../admin/site_notice/index.html.slime | 8 +-- .../admin/site_notice/new.html.slime | 2 +- .../admin/subnet_ban/edit.html.slime | 4 +- .../admin/subnet_ban/index.html.slime | 12 ++--- .../templates/admin/subnet_ban/new.html.slime | 4 +- .../templates/admin/user/_form.html.slime | 2 +- .../templates/admin/user/edit.html.slime | 2 +- .../admin/user/force_filter/new.html.slime | 2 +- .../templates/admin/user/index.html.slime | 16 +++--- .../templates/admin/user_ban/edit.html.slime | 4 +- .../templates/admin/user_ban/index.html.slime | 12 ++--- .../templates/admin/user_ban/new.html.slime | 4 +- .../templates/advert/_box.html.slime | 2 +- .../templates/api/rss/watched/index.html.eex | 8 +-- .../templates/avatar/edit.html.slime | 8 +-- .../templates/channel/_channel_box.html.slime | 10 ++-- .../templates/channel/edit.html.slime | 2 +- .../templates/channel/index.html.slime | 10 ++-- .../templates/channel/new.html.slime | 2 +- .../subscription/_subscription.html.slime | 6 +-- .../templates/comment/_comment.html.slime | 10 ++-- .../comment/_comment_options.html.slime | 8 +-- .../comment/_comment_with_image.html.slime | 6 +-- .../templates/comment/index.html.slime | 18 +++---- .../commission/_directory_results.html.slime | 8 +-- .../commission/_directory_sidebar.html.slime | 2 +- .../templates/confirmation/new.html.slime | 2 +- .../templates/conversation/index.html.slime | 8 +-- .../conversation/message/_form.html.slime | 2 +- .../templates/conversation/new.html.slime | 4 +- .../templates/conversation/show.html.slime | 16 +++--- .../templates/dnp_entry/edit.html.slime | 2 +- .../templates/dnp_entry/index.html.slime | 10 ++-- .../templates/dnp_entry/new.html.slime | 2 +- .../templates/dnp_entry/show.html.slime | 22 ++++---- .../duplicate_report/_form.html.slime | 2 +- .../duplicate_report/_image_cell.html.slime | 4 +- .../duplicate_report/_list.html.slime | 8 +-- .../duplicate_report/index.html.slime | 18 +++---- .../templates/filter/_filter.html.slime | 8 +-- .../templates/filter/edit.html.slime | 4 +- .../templates/filter/index.html.slime | 32 ++++++------ .../templates/filter/new.html.slime | 2 +- .../templates/filter/show.html.slime | 8 +-- .../fingerprint_profile/show.html.slime | 22 ++++---- .../source_change/index.html.slime | 2 +- .../tag_change/index.html.slime | 8 +-- .../templates/forum/index.html.slime | 8 +-- .../templates/forum/show.html.slime | 14 +++--- .../subscription/_subscription.html.slime | 6 +-- .../templates/gallery/_gallery.html.slime | 2 +- .../templates/gallery/edit.html.slime | 2 +- .../templates/gallery/index.html.slime | 4 +- .../templates/gallery/new.html.slime | 2 +- .../templates/gallery/show.html.slime | 14 +++--- .../subscription/_subscription.html.slime | 6 +-- .../image/_add_to_gallery_dropdown.html.slime | 14 +++--- .../templates/image/_image_box.html.slime | 2 +- .../image/_image_container.html.slime | 2 +- .../templates/image/_image_meta.html.slime | 10 ++-- .../templates/image/_image_target.html.slime | 4 +- .../templates/image/_options.html.slime | 42 ++++++++-------- .../templates/image/_random_button.html.slime | 2 +- .../templates/image/_source.html.slime | 6 +-- .../templates/image/_tags.html.slime | 4 +- .../templates/image/_uploader.html.slime | 6 +-- .../templates/image/comment/_form.html.slime | 2 +- .../templates/image/comment/edit.html.slime | 2 +- .../image/comment/history/index.html.slime | 2 +- .../templates/image/comment/index.html.slime | 2 +- .../templates/image/deleted.html.slime | 2 +- .../image/description/_form.html.slime | 2 +- .../templates/image/favorite/index.html.slime | 12 ++--- .../templates/image/index.html.slime | 6 +-- .../templates/image/new.html.slime | 2 +- .../templates/image/related/index.html.slime | 2 +- .../templates/image/reporting/show.html.slime | 4 +- .../image/scratchpad/edit.html.slime | 4 +- .../templates/image/show.html.slime | 2 +- .../image/source_change/index.html.slime | 4 +- .../subscription/_subscription.html.slime | 6 +-- .../image/tag_change/index.html.slime | 10 ++-- .../templates/image/tag_lock/show.html.slime | 2 +- .../templates/ip_profile/show.html.slime | 22 ++++---- .../ip_profile/source_change/index.html.slime | 2 +- .../ip_profile/tag_change/index.html.slime | 8 +-- .../templates/layout/_header.html.slime | 22 ++++---- .../layout/_header_navigation.html.slime | 2 +- .../layout/_header_staff_links.html.slime | 32 ++++++------ .../templates/layout/_opengraph.html.slime | 6 +-- .../templates/message/_message.html.slime | 2 +- .../templates/moderation_log/index.html.slime | 2 +- .../notification/_channel.html.slime | 6 +-- .../templates/notification/_forum.html.slime | 8 +-- .../notification/_gallery.html.slime | 6 +-- .../templates/notification/_image.html.slime | 6 +-- .../templates/notification/_topic.html.slime | 6 +-- .../templates/notification/index.html.slime | 2 +- .../templates/page/edit.html.slime | 2 +- .../templates/page/history/index.html.slime | 4 +- .../templates/page/index.html.slime | 4 +- .../templates/page/new.html.slime | 2 +- .../templates/page/show.html.slime | 4 +- .../templates/password/edit.html.slime | 2 +- .../templates/password/new.html.slime | 2 +- .../templates/post/_post.html.slime | 10 ++-- .../templates/post/_post_options.html.slime | 8 +-- .../templates/post/index.html.slime | 32 ++++++------ .../templates/profile/_about_me.html.slime | 2 +- .../templates/profile/_admin_block.html.slime | 50 +++++++++---------- .../templates/profile/_commission.html.slime | 6 +-- .../profile/_recent_comments.html.slime | 2 +- .../profile/_recent_galleries.html.slime | 2 +- .../profile/_recent_posts.html.slime | 6 +-- .../profile/alias/_aliases.html.slime | 2 +- .../profile/artist_link/edit.html.slime | 2 +- .../profile/artist_link/index.html.slime | 4 +- .../profile/artist_link/new.html.slime | 2 +- .../profile/artist_link/show.html.slime | 10 ++-- .../templates/profile/award/edit.html.slime | 2 +- .../templates/profile/award/new.html.slime | 2 +- .../commission/_listing_items.html.slime | 8 +-- .../commission/_listing_sidebar.html.slime | 8 +-- .../profile/commission/edit.html.slime | 4 +- .../profile/commission/item/edit.html.slime | 4 +- .../profile/commission/item/new.html.slime | 4 +- .../profile/commission/new.html.slime | 4 +- .../profile/description/edit.html.slime | 2 +- .../templates/profile/detail/index.html.slime | 10 ++-- .../profile/fp_history/index.html.slime | 2 +- .../profile/ip_history/index.html.slime | 2 +- .../profile/scratchpad/edit.html.slime | 2 +- .../templates/profile/show.html.slime | 50 +++++++++---------- .../profile/source_change/index.html.slime | 4 +- .../profile/tag_change/index.html.slime | 12 ++--- .../templates/registration/edit.html.slime | 10 ++-- .../registration/name/edit.html.slime | 4 +- .../templates/registration/new.html.slime | 2 +- .../registration/totp/edit.html.slime | 4 +- .../templates/report/index.html.slime | 2 +- .../templates/search/_form.html.slime | 2 +- .../templates/search/index.html.slime | 2 +- .../templates/search/reverse/index.html.slime | 4 +- .../templates/session/new.html.slime | 8 +-- .../templates/session/totp/new.html.slime | 2 +- .../templates/setting/edit.html.slime | 6 +-- .../templates/source_change/index.html.slime | 2 +- .../templates/staff/index.html.slime | 4 +- .../templates/tag/_tag.html.slime | 12 ++--- .../templates/tag/_tag_info_row.html.slime | 24 ++++----- .../templates/tag/alias/edit.html.slime | 6 +-- .../templates/tag/detail/_filters.html.slime | 4 +- .../templates/tag/detail/index.html.slime | 4 +- .../templates/tag/edit.html.slime | 10 ++-- .../templates/tag/image/edit.html.slime | 6 +-- .../templates/tag/index.html.slime | 34 ++++++------- .../templates/tag/show.html.slime | 2 +- .../templates/tag/tag_change/index.html.slime | 10 ++-- .../templates/tag_change/index.html.slime | 6 +-- .../templates/topic/new.html.slime | 2 +- .../templates/topic/poll/_display.html.slime | 4 +- .../topic/poll/_vote_form.html.slime | 2 +- .../templates/topic/poll/edit.html.slime | 2 +- .../topic/poll/vote/index.html.slime | 4 +- .../templates/topic/post/_form.html.slime | 2 +- .../templates/topic/post/edit.html.slime | 2 +- .../topic/post/history/index.html.slime | 2 +- .../templates/topic/show.html.slime | 28 +++++------ .../subscription/_subscription.html.slime | 6 +-- .../templates/unlock/new.html.slime | 2 +- .../user_attribution/_anon_user.html.slime | 4 +- .../user_attribution/_user.html.slime | 2 +- lib/philomena_web/user_auth.ex | 2 +- .../views/admin/mod_note_view.ex | 8 +-- lib/philomena_web/views/admin/report_view.ex | 4 +- lib/philomena_web/views/conversation_view.ex | 2 +- lib/philomena_web/views/profile_view.ex | 2 +- lib/philomena_web/views/report_view.ex | 14 +++--- .../confirmation_controller_test.exs | 14 +++--- .../controllers/password_controller_test.exs | 18 +++---- .../registration/email_controller_test.exs | 22 ++++---- .../registration/password_controller_test.exs | 8 +-- .../registration_controller_test.exs | 14 +++--- .../controllers/session_controller_test.exs | 12 ++--- .../controllers/unlock_controller_test.exs | 14 +++--- test/philomena_web/user_auth_test.exs | 2 +- 331 files changed, 1034 insertions(+), 1056 deletions(-) diff --git a/lib/philomena_web/controllers/admin/advert/image_controller.ex b/lib/philomena_web/controllers/admin/advert/image_controller.ex index 8fe46022..c3bae8c0 100644 --- a/lib/philomena_web/controllers/admin/advert/image_controller.ex +++ b/lib/philomena_web/controllers/admin/advert/image_controller.ex @@ -22,7 +22,7 @@ defmodule PhilomenaWeb.Admin.Advert.ImageController do {:ok, _advert} -> conn |> put_flash(:info, "Advert was successfully updated.") - |> redirect(to: Routes.admin_advert_path(conn, :index)) + |> redirect(to: ~p"/admin/adverts") {:error, changeset} -> render(conn, "edit.html", changeset: changeset) diff --git a/lib/philomena_web/controllers/admin/advert_controller.ex b/lib/philomena_web/controllers/admin/advert_controller.ex index bb119f42..e058ce26 100644 --- a/lib/philomena_web/controllers/admin/advert_controller.ex +++ b/lib/philomena_web/controllers/admin/advert_controller.ex @@ -32,7 +32,7 @@ defmodule PhilomenaWeb.Admin.AdvertController do {:ok, _advert} -> conn |> put_flash(:info, "Advert was successfully created.") - |> redirect(to: Routes.admin_advert_path(conn, :index)) + |> redirect(to: ~p"/admin/adverts") {:error, :advert, changeset, _changes} -> render(conn, "new.html", changeset: changeset) @@ -49,7 +49,7 @@ defmodule PhilomenaWeb.Admin.AdvertController do {:ok, _advert} -> conn |> put_flash(:info, "Advert was successfully updated.") - |> redirect(to: Routes.admin_advert_path(conn, :index)) + |> redirect(to: ~p"/admin/adverts") {:error, changeset} -> render(conn, "edit.html", changeset: changeset) @@ -61,7 +61,7 @@ defmodule PhilomenaWeb.Admin.AdvertController do conn |> put_flash(:info, "Advert was successfully deleted.") - |> redirect(to: Routes.admin_advert_path(conn, :index)) + |> redirect(to: ~p"/admin/adverts") end defp verify_authorized(conn, _opts) do diff --git a/lib/philomena_web/controllers/admin/artist_link/contact_controller.ex b/lib/philomena_web/controllers/admin/artist_link/contact_controller.ex index 98efb1f4..0e0ffc30 100644 --- a/lib/philomena_web/controllers/admin/artist_link/contact_controller.ex +++ b/lib/philomena_web/controllers/admin/artist_link/contact_controller.ex @@ -19,13 +19,13 @@ defmodule PhilomenaWeb.Admin.ArtistLink.ContactController do conn |> put_flash(:info, "Artist successfully marked as contacted.") |> moderation_log(details: &log_details/3, data: artist_link) - |> redirect(to: Routes.admin_artist_link_path(conn, :index)) + |> redirect(to: ~p"/admin/artist_links") end defp log_details(conn, _action, artist_link) do %{ body: "Contacted artist #{artist_link.user.name} at #{artist_link.uri}", - subject_path: Routes.profile_artist_link_path(conn, :show, artist_link.user, artist_link) + subject_path: ~p"/profiles/#{artist_link.user}/artist_links/#{artist_link}" } end end diff --git a/lib/philomena_web/controllers/admin/artist_link/reject_controller.ex b/lib/philomena_web/controllers/admin/artist_link/reject_controller.ex index 9bf92139..168251fd 100644 --- a/lib/philomena_web/controllers/admin/artist_link/reject_controller.ex +++ b/lib/philomena_web/controllers/admin/artist_link/reject_controller.ex @@ -18,13 +18,13 @@ defmodule PhilomenaWeb.Admin.ArtistLink.RejectController do conn |> put_flash(:info, "Artist link successfully marked as rejected.") |> moderation_log(details: &log_details/3, data: artist_link) - |> redirect(to: Routes.admin_artist_link_path(conn, :index)) + |> redirect(to: ~p"/admin/artist_links") end defp log_details(conn, _action, artist_link) do %{ body: "Rejected artist link #{artist_link.uri} created by #{artist_link.user.name}", - subject_path: Routes.profile_artist_link_path(conn, :show, artist_link.user, artist_link) + subject_path: ~p"/profiles/#{artist_link.user}/artist_links/#{artist_link}" } end end diff --git a/lib/philomena_web/controllers/admin/artist_link/verification_controller.ex b/lib/philomena_web/controllers/admin/artist_link/verification_controller.ex index a4cc1fce..02a45ab4 100644 --- a/lib/philomena_web/controllers/admin/artist_link/verification_controller.ex +++ b/lib/philomena_web/controllers/admin/artist_link/verification_controller.ex @@ -19,13 +19,13 @@ defmodule PhilomenaWeb.Admin.ArtistLink.VerificationController do conn |> put_flash(:info, "Artist link successfully verified.") |> moderation_log(details: &log_details/3, data: result.artist_link) - |> redirect(to: Routes.admin_artist_link_path(conn, :index)) + |> redirect(to: ~p"/admin/artist_links") end defp log_details(conn, _action, artist_link) do %{ body: "Verified artist link #{artist_link.uri} created by #{artist_link.user.name}", - subject_path: Routes.profile_artist_link_path(conn, :show, artist_link.user, artist_link) + subject_path: ~p"/profiles/#{artist_link.user}/artist_links/#{artist_link}" } end end diff --git a/lib/philomena_web/controllers/admin/badge/image_controller.ex b/lib/philomena_web/controllers/admin/badge/image_controller.ex index abdac0a2..069b8f0b 100644 --- a/lib/philomena_web/controllers/admin/badge/image_controller.ex +++ b/lib/philomena_web/controllers/admin/badge/image_controller.ex @@ -17,7 +17,7 @@ defmodule PhilomenaWeb.Admin.Badge.ImageController do {:ok, _badge} -> conn |> put_flash(:info, "Badge updated successfully.") - |> redirect(to: Routes.admin_badge_path(conn, :index)) + |> redirect(to: ~p"/admin/badges") {:error, :badge, changeset, _changes} -> render(conn, "edit.html", changeset: changeset) diff --git a/lib/philomena_web/controllers/admin/badge_controller.ex b/lib/philomena_web/controllers/admin/badge_controller.ex index 2aa79e31..f253f647 100644 --- a/lib/philomena_web/controllers/admin/badge_controller.ex +++ b/lib/philomena_web/controllers/admin/badge_controller.ex @@ -28,7 +28,7 @@ defmodule PhilomenaWeb.Admin.BadgeController do {:ok, _badge} -> conn |> put_flash(:info, "Badge created successfully.") - |> redirect(to: Routes.admin_badge_path(conn, :index)) + |> redirect(to: ~p"/admin/badges") {:error, :badge, changeset, _changes} -> render(conn, "new.html", changeset: changeset) @@ -45,7 +45,7 @@ defmodule PhilomenaWeb.Admin.BadgeController do {:ok, _badge} -> conn |> put_flash(:info, "Badge updated successfully.") - |> redirect(to: Routes.admin_badge_path(conn, :index)) + |> redirect(to: ~p"/admin/badges") {:error, :badge, changeset, _changes} -> render(conn, "edit.html", changeset: changeset) diff --git a/lib/philomena_web/controllers/admin/batch/tag_controller.ex b/lib/philomena_web/controllers/admin/batch/tag_controller.ex index 4ae3c714..59371b6a 100644 --- a/lib/philomena_web/controllers/admin/batch/tag_controller.ex +++ b/lib/philomena_web/controllers/admin/batch/tag_controller.ex @@ -71,7 +71,7 @@ defmodule PhilomenaWeb.Admin.Batch.TagController do defp log_details(conn, _action, data) do %{ body: "Batch tagged '#{data.tag_list}' on #{data.image_count} images", - subject_path: Routes.profile_path(conn, :show, conn.assigns.current_user) + subject_path: ~p"/profiles/#{conn.assigns.current_user}" } end end diff --git a/lib/philomena_web/controllers/admin/dnp_entry/transition_controller.ex b/lib/philomena_web/controllers/admin/dnp_entry/transition_controller.ex index a774ece0..8f0fc52e 100644 --- a/lib/philomena_web/controllers/admin/dnp_entry/transition_controller.ex +++ b/lib/philomena_web/controllers/admin/dnp_entry/transition_controller.ex @@ -16,12 +16,12 @@ defmodule PhilomenaWeb.Admin.DnpEntry.TransitionController do {:ok, dnp_entry} -> conn |> put_flash(:info, "Successfully updated DNP entry.") - |> redirect(to: Routes.dnp_entry_path(conn, :show, dnp_entry)) + |> redirect(to: ~p"/dnp/#{dnp_entry}") {:error, _changeset} -> conn |> put_flash(:error, "Failed to update DNP entry!") - |> redirect(to: Routes.dnp_entry_path(conn, :show, conn.assigns.dnp_entry)) + |> redirect(to: ~p"/dnp/#{conn.assigns.dnp_entry}") end end diff --git a/lib/philomena_web/controllers/admin/donation_controller.ex b/lib/philomena_web/controllers/admin/donation_controller.ex index 91de59cf..2274daff 100644 --- a/lib/philomena_web/controllers/admin/donation_controller.ex +++ b/lib/philomena_web/controllers/admin/donation_controller.ex @@ -23,12 +23,12 @@ defmodule PhilomenaWeb.Admin.DonationController do {:ok, _donation} -> conn |> put_flash(:info, "Donation successfully created.") - |> redirect(to: Routes.admin_donation_path(conn, :index)) + |> redirect(to: ~p"/admin/donations") _error -> conn |> put_flash(:error, "Error creating donation!") - |> redirect(to: Routes.admin_donation_path(conn, :index)) + |> redirect(to: ~p"/admin/donations") end end diff --git a/lib/philomena_web/controllers/admin/fingerprint_ban_controller.ex b/lib/philomena_web/controllers/admin/fingerprint_ban_controller.ex index 5cb4ccd0..2e1c20f9 100644 --- a/lib/philomena_web/controllers/admin/fingerprint_ban_controller.ex +++ b/lib/philomena_web/controllers/admin/fingerprint_ban_controller.ex @@ -48,7 +48,7 @@ defmodule PhilomenaWeb.Admin.FingerprintBanController do conn |> put_flash(:info, "Fingerprint was successfully banned.") |> moderation_log(details: &log_details/3, data: fingerprint_ban) - |> redirect(to: Routes.admin_fingerprint_ban_path(conn, :index)) + |> redirect(to: ~p"/admin/fingerprint_bans") {:error, changeset} -> render(conn, "new.html", changeset: changeset) @@ -66,7 +66,7 @@ defmodule PhilomenaWeb.Admin.FingerprintBanController do conn |> put_flash(:info, "Fingerprint ban successfully updated.") |> moderation_log(details: &log_details/3, data: fingerprint_ban) - |> redirect(to: Routes.admin_fingerprint_ban_path(conn, :index)) + |> redirect(to: ~p"/admin/fingerprint_bans") {:error, changeset} -> render(conn, "edit.html", changeset: changeset) @@ -79,7 +79,7 @@ defmodule PhilomenaWeb.Admin.FingerprintBanController do conn |> put_flash(:info, "Fingerprint ban successfully deleted.") |> moderation_log(details: &log_details/3, data: fingerprint_ban) - |> redirect(to: Routes.admin_fingerprint_ban_path(conn, :index)) + |> redirect(to: ~p"/admin/fingerprint_bans") end defp load_bans(queryable, conn) do @@ -118,6 +118,6 @@ defmodule PhilomenaWeb.Admin.FingerprintBanController do :delete -> "Deleted a fingerprint ban #{ban.generated_ban_id}" end - %{body: body, subject_path: Routes.admin_fingerprint_ban_path(conn, :index)} + %{body: body, subject_path: ~p"/admin/fingerprint_bans"} end end diff --git a/lib/philomena_web/controllers/admin/forum_controller.ex b/lib/philomena_web/controllers/admin/forum_controller.ex index 7d9e0190..5c40e4c4 100644 --- a/lib/philomena_web/controllers/admin/forum_controller.ex +++ b/lib/philomena_web/controllers/admin/forum_controller.ex @@ -21,7 +21,7 @@ defmodule PhilomenaWeb.Admin.ForumController do {:ok, _forum} -> conn |> put_flash(:info, "Forum created successfully.") - |> redirect(to: Routes.admin_forum_path(conn, :index)) + |> redirect(to: ~p"/admin/forums") {:error, changeset} -> render(conn, "new.html", changeset: changeset) @@ -38,7 +38,7 @@ defmodule PhilomenaWeb.Admin.ForumController do {:ok, _forum} -> conn |> put_flash(:info, "Forum updated successfully.") - |> redirect(to: Routes.admin_forum_path(conn, :index)) + |> redirect(to: ~p"/admin/forums") {:error, changeset} -> render(conn, "edit.html", changeset: changeset) diff --git a/lib/philomena_web/controllers/admin/mod_note_controller.ex b/lib/philomena_web/controllers/admin/mod_note_controller.ex index 23f71815..f5b3999f 100644 --- a/lib/philomena_web/controllers/admin/mod_note_controller.ex +++ b/lib/philomena_web/controllers/admin/mod_note_controller.ex @@ -46,7 +46,7 @@ defmodule PhilomenaWeb.Admin.ModNoteController do {:ok, _mod_note} -> conn |> put_flash(:info, "Successfully created mod note.") - |> redirect(to: Routes.admin_mod_note_path(conn, :index)) + |> redirect(to: ~p"/admin/mod_notes") {:error, changeset} -> render(conn, "new.html", changeset: changeset) @@ -63,7 +63,7 @@ defmodule PhilomenaWeb.Admin.ModNoteController do {:ok, _mod_note} -> conn |> put_flash(:info, "Successfully updated mod note.") - |> redirect(to: Routes.admin_mod_note_path(conn, :index)) + |> redirect(to: ~p"/admin/mod_notes") {:error, changeset} -> render(conn, "edit.html", changeset: changeset) @@ -75,7 +75,7 @@ defmodule PhilomenaWeb.Admin.ModNoteController do conn |> put_flash(:info, "Successfully deleted mod note.") - |> redirect(to: Routes.admin_mod_note_path(conn, :index)) + |> redirect(to: ~p"/admin/mod_notes") end defp verify_authorized(conn, _opts) do diff --git a/lib/philomena_web/controllers/admin/report/claim_controller.ex b/lib/philomena_web/controllers/admin/report/claim_controller.ex index 93880a22..76702b2e 100644 --- a/lib/philomena_web/controllers/admin/report/claim_controller.ex +++ b/lib/philomena_web/controllers/admin/report/claim_controller.ex @@ -12,12 +12,12 @@ defmodule PhilomenaWeb.Admin.Report.ClaimController do {:ok, _report} -> conn |> put_flash(:info, "Successfully marked report as in progress") - |> redirect(to: Routes.admin_report_path(conn, :index)) + |> redirect(to: ~p"/admin/reports") {:error, _changeset} -> conn |> put_flash(:error, "Couldn't claim that report!") - |> redirect(to: Routes.admin_report_path(conn, :show, conn.assigns.report)) + |> redirect(to: ~p"/admin/reports/#{conn.assigns.report}") end end @@ -26,6 +26,6 @@ defmodule PhilomenaWeb.Admin.Report.ClaimController do conn |> put_flash(:info, "Successfully released report.") - |> redirect(to: Routes.admin_report_path(conn, :show, report)) + |> redirect(to: ~p"/admin/reports/#{report}") end end diff --git a/lib/philomena_web/controllers/admin/report/close_controller.ex b/lib/philomena_web/controllers/admin/report/close_controller.ex index dedb4d2d..75f1e7ff 100644 --- a/lib/philomena_web/controllers/admin/report/close_controller.ex +++ b/lib/philomena_web/controllers/admin/report/close_controller.ex @@ -12,6 +12,6 @@ defmodule PhilomenaWeb.Admin.Report.CloseController do conn |> put_flash(:info, "Successfully closed report") - |> redirect(to: Routes.admin_report_path(conn, :index)) + |> redirect(to: ~p"/admin/reports") end end diff --git a/lib/philomena_web/controllers/admin/site_notice_controller.ex b/lib/philomena_web/controllers/admin/site_notice_controller.ex index 11462540..7612422e 100644 --- a/lib/philomena_web/controllers/admin/site_notice_controller.ex +++ b/lib/philomena_web/controllers/admin/site_notice_controller.ex @@ -28,7 +28,7 @@ defmodule PhilomenaWeb.Admin.SiteNoticeController do {:ok, _site_notice} -> conn |> put_flash(:info, "Successfully created site notice.") - |> redirect(to: Routes.admin_site_notice_path(conn, :index)) + |> redirect(to: ~p"/admin/site_notices") {:error, changeset} -> render(conn, "new.html", changeset: changeset) @@ -45,7 +45,7 @@ defmodule PhilomenaWeb.Admin.SiteNoticeController do {:ok, _site_notice} -> conn |> put_flash(:info, "Succesfully updated site notice.") - |> redirect(to: Routes.admin_site_notice_path(conn, :index)) + |> redirect(to: ~p"/admin/site_notices") {:error, changeset} -> render(conn, "edit.html", changeset: changeset) @@ -57,7 +57,7 @@ defmodule PhilomenaWeb.Admin.SiteNoticeController do conn |> put_flash(:info, "Sucessfully deleted site notice.") - |> redirect(to: Routes.admin_site_notice_path(conn, :index)) + |> redirect(to: ~p"/admin/site_notices") end defp verify_authorized(conn, _opts) do diff --git a/lib/philomena_web/controllers/admin/subnet_ban_controller.ex b/lib/philomena_web/controllers/admin/subnet_ban_controller.ex index 93c42807..f2d0dbaa 100644 --- a/lib/philomena_web/controllers/admin/subnet_ban_controller.ex +++ b/lib/philomena_web/controllers/admin/subnet_ban_controller.ex @@ -50,7 +50,7 @@ defmodule PhilomenaWeb.Admin.SubnetBanController do conn |> put_flash(:info, "Subnet was successfully banned.") |> moderation_log(details: &log_details/3, data: subnet_ban) - |> redirect(to: Routes.admin_subnet_ban_path(conn, :index)) + |> redirect(to: ~p"/admin/subnet_bans") {:error, changeset} -> render(conn, "new.html", changeset: changeset) @@ -68,7 +68,7 @@ defmodule PhilomenaWeb.Admin.SubnetBanController do conn |> put_flash(:info, "Subnet ban successfully updated.") |> moderation_log(details: &log_details/3, data: subnet_ban) - |> redirect(to: Routes.admin_subnet_ban_path(conn, :index)) + |> redirect(to: ~p"/admin/subnet_bans") {:error, changeset} -> render(conn, "edit.html", changeset: changeset) @@ -81,7 +81,7 @@ defmodule PhilomenaWeb.Admin.SubnetBanController do conn |> put_flash(:info, "Subnet ban successfully deleted.") |> moderation_log(details: &log_details/3, data: subnet_ban) - |> redirect(to: Routes.admin_subnet_ban_path(conn, :index)) + |> redirect(to: ~p"/admin/subnet_bans") end defp load_bans(queryable, conn) do @@ -120,6 +120,6 @@ defmodule PhilomenaWeb.Admin.SubnetBanController do :delete -> "Deleted a subnet ban #{ban.generated_ban_id}" end - %{body: body, subject_path: Routes.admin_subnet_ban_path(conn, :index)} + %{body: body, subject_path: ~p"/admin/subnet_bans"} end end diff --git a/lib/philomena_web/controllers/admin/user/activation_controller.ex b/lib/philomena_web/controllers/admin/user/activation_controller.ex index e5f78aad..f261ab1b 100644 --- a/lib/philomena_web/controllers/admin/user/activation_controller.ex +++ b/lib/philomena_web/controllers/admin/user/activation_controller.ex @@ -12,7 +12,7 @@ defmodule PhilomenaWeb.Admin.User.ActivationController do conn |> put_flash(:info, "User was reactivated.") - |> redirect(to: Routes.profile_path(conn, :show, user)) + |> redirect(to: ~p"/profiles/#{user}") end def delete(conn, _params) do @@ -20,7 +20,7 @@ defmodule PhilomenaWeb.Admin.User.ActivationController do conn |> put_flash(:info, "User was deactivated.") - |> redirect(to: Routes.profile_path(conn, :show, user)) + |> redirect(to: ~p"/profiles/#{user}") end defp verify_authorized(conn, _opts) do diff --git a/lib/philomena_web/controllers/admin/user/api_key_controller.ex b/lib/philomena_web/controllers/admin/user/api_key_controller.ex index e2987ff9..19b1eb64 100644 --- a/lib/philomena_web/controllers/admin/user/api_key_controller.ex +++ b/lib/philomena_web/controllers/admin/user/api_key_controller.ex @@ -12,7 +12,7 @@ defmodule PhilomenaWeb.Admin.User.ApiKeyController do conn |> put_flash(:info, "API token successfully reset.") - |> redirect(to: Routes.profile_path(conn, :show, user)) + |> redirect(to: ~p"/profiles/#{user}") end defp verify_authorized(conn, _opts) do diff --git a/lib/philomena_web/controllers/admin/user/avatar_controller.ex b/lib/philomena_web/controllers/admin/user/avatar_controller.ex index c04fdbcd..80c1e262 100644 --- a/lib/philomena_web/controllers/admin/user/avatar_controller.ex +++ b/lib/philomena_web/controllers/admin/user/avatar_controller.ex @@ -12,7 +12,7 @@ defmodule PhilomenaWeb.Admin.User.AvatarController do conn |> put_flash(:info, "Successfully removed avatar.") - |> redirect(to: Routes.admin_user_path(conn, :edit, conn.assigns.user)) + |> redirect(to: ~p"/admin/users/#{conn.assigns.user}/edit") end defp verify_authorized(conn, _opts) do diff --git a/lib/philomena_web/controllers/admin/user/downvote_controller.ex b/lib/philomena_web/controllers/admin/user/downvote_controller.ex index 1dfdaff8..df5cb145 100644 --- a/lib/philomena_web/controllers/admin/user/downvote_controller.ex +++ b/lib/philomena_web/controllers/admin/user/downvote_controller.ex @@ -12,7 +12,7 @@ defmodule PhilomenaWeb.Admin.User.DownvoteController do conn |> put_flash(:info, "Downvote wipe started.") - |> redirect(to: Routes.profile_path(conn, :show, conn.assigns.user)) + |> redirect(to: ~p"/profiles/#{conn.assigns.user}") end defp verify_authorized(conn, _opts) do diff --git a/lib/philomena_web/controllers/admin/user/force_filter_controller.ex b/lib/philomena_web/controllers/admin/user/force_filter_controller.ex index 049d68fb..74266ef5 100644 --- a/lib/philomena_web/controllers/admin/user/force_filter_controller.ex +++ b/lib/philomena_web/controllers/admin/user/force_filter_controller.ex @@ -18,7 +18,7 @@ defmodule PhilomenaWeb.Admin.User.ForceFilterController do conn |> put_flash(:info, "Filter was forced.") - |> redirect(to: Routes.profile_path(conn, :show, user)) + |> redirect(to: ~p"/profiles/#{user}") end def delete(conn, _params) do @@ -26,7 +26,7 @@ defmodule PhilomenaWeb.Admin.User.ForceFilterController do conn |> put_flash(:info, "Forced filter was removed.") - |> redirect(to: Routes.profile_path(conn, :show, user)) + |> redirect(to: ~p"/profiles/#{user}") end defp verify_authorized(conn, _opts) do diff --git a/lib/philomena_web/controllers/admin/user/unlock_controller.ex b/lib/philomena_web/controllers/admin/user/unlock_controller.ex index 0c36122e..54610fda 100644 --- a/lib/philomena_web/controllers/admin/user/unlock_controller.ex +++ b/lib/philomena_web/controllers/admin/user/unlock_controller.ex @@ -12,7 +12,7 @@ defmodule PhilomenaWeb.Admin.User.UnlockController do conn |> put_flash(:info, "User was unlocked.") - |> redirect(to: Routes.profile_path(conn, :show, user)) + |> redirect(to: ~p"/profiles/#{user}") end defp verify_authorized(conn, _opts) do diff --git a/lib/philomena_web/controllers/admin/user/verification_controller.ex b/lib/philomena_web/controllers/admin/user/verification_controller.ex index 982a520c..9478bc42 100644 --- a/lib/philomena_web/controllers/admin/user/verification_controller.ex +++ b/lib/philomena_web/controllers/admin/user/verification_controller.ex @@ -13,7 +13,7 @@ defmodule PhilomenaWeb.Admin.User.VerificationController do conn |> put_flash(:info, "User verification granted.") |> moderation_log(details: &log_details/3, data: user) - |> redirect(to: Routes.profile_path(conn, :show, user)) + |> redirect(to: ~p"/profiles/#{user}") end def delete(conn, _params) do @@ -22,7 +22,7 @@ defmodule PhilomenaWeb.Admin.User.VerificationController do conn |> put_flash(:info, "User verification revoked.") |> moderation_log(details: &log_details/3, data: user) - |> redirect(to: Routes.profile_path(conn, :show, user)) + |> redirect(to: ~p"/profiles/#{user}") end defp verify_authorized(conn, _opts) do @@ -39,6 +39,6 @@ defmodule PhilomenaWeb.Admin.User.VerificationController do :delete -> "Revoked verification from #{user.name}" end - %{body: body, subject_path: Routes.profile_path(conn, :show, user)} + %{body: body, subject_path: ~p"/profiles/#{user}"} end end diff --git a/lib/philomena_web/controllers/admin/user/vote_controller.ex b/lib/philomena_web/controllers/admin/user/vote_controller.ex index bcb9318a..310f3575 100644 --- a/lib/philomena_web/controllers/admin/user/vote_controller.ex +++ b/lib/philomena_web/controllers/admin/user/vote_controller.ex @@ -12,7 +12,7 @@ defmodule PhilomenaWeb.Admin.User.VoteController do conn |> put_flash(:info, "Vote and fave wipe started.") - |> redirect(to: Routes.profile_path(conn, :show, conn.assigns.user)) + |> redirect(to: ~p"/profiles/#{conn.assigns.user}") end defp verify_authorized(conn, _opts) do diff --git a/lib/philomena_web/controllers/admin/user/wipe_controller.ex b/lib/philomena_web/controllers/admin/user/wipe_controller.ex index 86301f4d..3bc64a82 100644 --- a/lib/philomena_web/controllers/admin/user/wipe_controller.ex +++ b/lib/philomena_web/controllers/admin/user/wipe_controller.ex @@ -15,7 +15,7 @@ defmodule PhilomenaWeb.Admin.User.WipeController do :info, "PII wipe queued, please verify and then deactivate the account as necessary." ) - |> redirect(to: Routes.profile_path(conn, :show, conn.assigns.user)) + |> redirect(to: ~p"/profiles/#{conn.assigns.user}") end defp verify_authorized(conn, _opts) do diff --git a/lib/philomena_web/controllers/admin/user_ban_controller.ex b/lib/philomena_web/controllers/admin/user_ban_controller.ex index f98c3337..bbaf6b62 100644 --- a/lib/philomena_web/controllers/admin/user_ban_controller.ex +++ b/lib/philomena_web/controllers/admin/user_ban_controller.ex @@ -51,7 +51,7 @@ defmodule PhilomenaWeb.Admin.UserBanController do conn |> put_flash(:info, "User was successfully banned.") |> moderation_log(details: &log_details/3, data: user_ban) - |> redirect(to: Routes.admin_user_ban_path(conn, :index)) + |> redirect(to: ~p"/admin/user_bans") {:error, :user_ban, changeset, _changes} -> render(conn, "new.html", changeset: changeset) @@ -72,7 +72,7 @@ defmodule PhilomenaWeb.Admin.UserBanController do conn |> put_flash(:info, "User ban successfully updated.") |> moderation_log(details: &log_details/3, data: user_ban) - |> redirect(to: Routes.admin_user_ban_path(conn, :index)) + |> redirect(to: ~p"/admin/user_bans") {:error, changeset} -> render(conn, "edit.html", changeset: changeset) @@ -85,7 +85,7 @@ defmodule PhilomenaWeb.Admin.UserBanController do conn |> put_flash(:info, "User ban successfully deleted.") |> moderation_log(details: &log_details/3, data: user_ban) - |> redirect(to: Routes.admin_user_ban_path(conn, :index)) + |> redirect(to: ~p"/admin/user_bans") end defp load_bans(queryable, conn) do @@ -124,6 +124,6 @@ defmodule PhilomenaWeb.Admin.UserBanController do :delete -> "Deleted a user ban #{ban.generated_ban_id}" end - %{body: body, subject_path: Routes.admin_user_ban_path(conn, :index)} + %{body: body, subject_path: ~p"/admin/user_bans"} end end diff --git a/lib/philomena_web/controllers/admin/user_controller.ex b/lib/philomena_web/controllers/admin/user_controller.ex index fe31d2f4..672147f8 100644 --- a/lib/philomena_web/controllers/admin/user_controller.ex +++ b/lib/philomena_web/controllers/admin/user_controller.ex @@ -63,7 +63,7 @@ defmodule PhilomenaWeb.Admin.UserController do conn |> put_flash(:info, "User successfully updated.") |> moderation_log(details: &log_details/3, data: user) - |> redirect(to: Routes.profile_path(conn, :show, user)) + |> redirect(to: ~p"/profiles/#{user}") {:error, changeset} -> render(conn, "edit.html", changeset: changeset) @@ -84,7 +84,7 @@ defmodule PhilomenaWeb.Admin.UserController do defp log_details(conn, _action, user) do %{ body: "Updated user details for #{user.name}", - subject_path: Routes.profile_path(conn, :show, user) + subject_path: ~p"/profiles/#{user}" } end end diff --git a/lib/philomena_web/controllers/avatar_controller.ex b/lib/philomena_web/controllers/avatar_controller.ex index 50a30cf2..9b6e4544 100644 --- a/lib/philomena_web/controllers/avatar_controller.ex +++ b/lib/philomena_web/controllers/avatar_controller.ex @@ -18,7 +18,7 @@ defmodule PhilomenaWeb.AvatarController do {:ok, _user} -> conn |> put_flash(:info, "Successfully updated avatar.") - |> redirect(to: Routes.avatar_path(conn, :edit)) + |> redirect(to: ~p"/avatar/edit") {:error, changeset} -> render(conn, "edit.html", changeset: changeset) @@ -30,6 +30,6 @@ defmodule PhilomenaWeb.AvatarController do conn |> put_flash(:info, "Successfully removed avatar.") - |> redirect(to: Routes.avatar_path(conn, :edit)) + |> redirect(to: ~p"/avatar/edit") end end diff --git a/lib/philomena_web/controllers/channel/nsfw_controller.ex b/lib/philomena_web/controllers/channel/nsfw_controller.ex index f695fb4d..31125122 100644 --- a/lib/philomena_web/controllers/channel/nsfw_controller.ex +++ b/lib/philomena_web/controllers/channel/nsfw_controller.ex @@ -7,14 +7,14 @@ defmodule PhilomenaWeb.Channel.NsfwController do conn |> set_cookie("chan_nsfw", "true") |> put_flash(:info, "Successfully updated channel visibility.") - |> redirect(to: Routes.channel_path(conn, :index)) + |> redirect(to: ~p"/channels") end def delete(conn, _params) do conn |> set_cookie("chan_nsfw", "false") |> put_flash(:info, "Successfully updated channel visibility.") - |> redirect(to: Routes.channel_path(conn, :index)) + |> redirect(to: ~p"/channels") end # Duplicated from setting controller diff --git a/lib/philomena_web/controllers/channel_controller.ex b/lib/philomena_web/controllers/channel_controller.ex index 973017d3..6d88d257 100644 --- a/lib/philomena_web/controllers/channel_controller.ex +++ b/lib/philomena_web/controllers/channel_controller.ex @@ -52,7 +52,7 @@ defmodule PhilomenaWeb.ChannelController do {:ok, _channel} -> conn |> put_flash(:info, "Channel created successfully.") - |> redirect(to: Routes.channel_path(conn, :index)) + |> redirect(to: ~p"/channels") {:error, changeset} -> render(conn, "new.html", changeset: changeset) @@ -69,7 +69,7 @@ defmodule PhilomenaWeb.ChannelController do {:ok, _channel} -> conn |> put_flash(:info, "Channel updated successfully.") - |> redirect(to: Routes.channel_path(conn, :index)) + |> redirect(to: ~p"/channels") {:error, changeset} -> render(conn, "edit.html", changeset: changeset) @@ -81,7 +81,7 @@ defmodule PhilomenaWeb.ChannelController do conn |> put_flash(:info, "Channel destroyed successfully.") - |> redirect(to: Routes.channel_path(conn, :index)) + |> redirect(to: ~p"/channels") end defp maybe_search(query, %{"cq" => cq}) when is_binary(cq) and cq != "" do diff --git a/lib/philomena_web/controllers/confirmation_controller.ex b/lib/philomena_web/controllers/confirmation_controller.ex index 2186bb8e..c22aa9ed 100644 --- a/lib/philomena_web/controllers/confirmation_controller.ex +++ b/lib/philomena_web/controllers/confirmation_controller.ex @@ -14,7 +14,7 @@ defmodule PhilomenaWeb.ConfirmationController do if user = Users.get_user_by_email(email) do Users.deliver_user_confirmation_instructions( user, - &Routes.confirmation_url(conn, :show, &1) + &url(~p"/confirmations/#{&1}") ) end diff --git a/lib/philomena_web/controllers/conversation/hide_controller.ex b/lib/philomena_web/controllers/conversation/hide_controller.ex index 44bd8bad..71480de6 100644 --- a/lib/philomena_web/controllers/conversation/hide_controller.ex +++ b/lib/philomena_web/controllers/conversation/hide_controller.ex @@ -20,7 +20,7 @@ defmodule PhilomenaWeb.Conversation.HideController do conn |> put_flash(:info, "Conversation hidden.") - |> redirect(to: Routes.conversation_path(conn, :index)) + |> redirect(to: ~p"/conversations") end def delete(conn, _params) do @@ -31,6 +31,6 @@ defmodule PhilomenaWeb.Conversation.HideController do conn |> put_flash(:info, "Conversation restored.") - |> redirect(to: Routes.conversation_path(conn, :show, conversation)) + |> redirect(to: ~p"/conversations/#{conversation}") end end diff --git a/lib/philomena_web/controllers/conversation/message_controller.ex b/lib/philomena_web/controllers/conversation/message_controller.ex index 7e238902..8bd44940 100644 --- a/lib/philomena_web/controllers/conversation/message_controller.ex +++ b/lib/philomena_web/controllers/conversation/message_controller.ex @@ -36,12 +36,12 @@ defmodule PhilomenaWeb.Conversation.MessageController do conn |> put_flash(:info, "Message successfully sent.") - |> redirect(to: Routes.conversation_path(conn, :show, conversation, page: page)) + |> redirect(to: ~p"/conversations/#{conversation}?#{[page: page]}") _error -> conn |> put_flash(:error, "There was an error posting your message") - |> redirect(to: Routes.conversation_path(conn, :show, conversation)) + |> redirect(to: ~p"/conversations/#{conversation}") end end end diff --git a/lib/philomena_web/controllers/conversation/read_controller.ex b/lib/philomena_web/controllers/conversation/read_controller.ex index 93a5601e..aa777274 100644 --- a/lib/philomena_web/controllers/conversation/read_controller.ex +++ b/lib/philomena_web/controllers/conversation/read_controller.ex @@ -20,7 +20,7 @@ defmodule PhilomenaWeb.Conversation.ReadController do conn |> put_flash(:info, "Conversation marked as read.") - |> redirect(to: Routes.conversation_path(conn, :show, conversation)) + |> redirect(to: ~p"/conversations/#{conversation}") end def delete(conn, _params) do @@ -31,6 +31,6 @@ defmodule PhilomenaWeb.Conversation.ReadController do conn |> put_flash(:info, "Conversation marked as unread.") - |> redirect(to: Routes.conversation_path(conn, :index)) + |> redirect(to: ~p"/conversations") end end diff --git a/lib/philomena_web/controllers/conversation/report_controller.ex b/lib/philomena_web/controllers/conversation/report_controller.ex index 634bed1a..dab81482 100644 --- a/lib/philomena_web/controllers/conversation/report_controller.ex +++ b/lib/philomena_web/controllers/conversation/report_controller.ex @@ -22,7 +22,7 @@ defmodule PhilomenaWeb.Conversation.ReportController do def new(conn, _params) do conversation = conn.assigns.conversation - action = Routes.conversation_report_path(conn, :create, conversation) + action = ~p"/conversations/#{conversation}/reports" changeset = %Report{reportable_type: "Conversation", reportable_id: conversation.id} @@ -40,7 +40,7 @@ defmodule PhilomenaWeb.Conversation.ReportController do def create(conn, params) do conversation = conn.assigns.conversation - action = Routes.conversation_report_path(conn, :create, conversation) + action = ~p"/conversations/#{conversation}/reports" ReportController.create(conn, action, conversation, "Conversation", params) end diff --git a/lib/philomena_web/controllers/conversation_controller.ex b/lib/philomena_web/controllers/conversation_controller.ex index 8b936f8e..12784b42 100644 --- a/lib/philomena_web/controllers/conversation_controller.ex +++ b/lib/philomena_web/controllers/conversation_controller.ex @@ -115,7 +115,7 @@ defmodule PhilomenaWeb.ConversationController do conn |> put_flash(:info, "Conversation successfully created.") - |> redirect(to: Routes.conversation_path(conn, :show, conversation)) + |> redirect(to: ~p"/conversations/#{conversation}") {:error, changeset} -> conn diff --git a/lib/philomena_web/controllers/dnp_entry_controller.ex b/lib/philomena_web/controllers/dnp_entry_controller.ex index ff3f1a07..d2e675b2 100644 --- a/lib/philomena_web/controllers/dnp_entry_controller.ex +++ b/lib/philomena_web/controllers/dnp_entry_controller.ex @@ -97,7 +97,7 @@ defmodule PhilomenaWeb.DnpEntryController do {:ok, dnp_entry} -> conn |> put_flash(:info, "Successfully submitted DNP request.") - |> redirect(to: Routes.dnp_entry_path(conn, :show, dnp_entry)) + |> redirect(to: ~p"/dnp/#{dnp_entry}") {:error, changeset} -> render(conn, "new.html", changeset: changeset) @@ -122,7 +122,7 @@ defmodule PhilomenaWeb.DnpEntryController do {:ok, dnp_entry} -> conn |> put_flash(:info, "Successfully updated DNP request.") - |> redirect(to: Routes.dnp_entry_path(conn, :show, dnp_entry)) + |> redirect(to: ~p"/dnp/#{dnp_entry}") {:error, changeset} -> render(conn, "edit.html", changeset: changeset) diff --git a/lib/philomena_web/controllers/duplicate_report/accept_controller.ex b/lib/philomena_web/controllers/duplicate_report/accept_controller.ex index 2b21e306..a67760dc 100644 --- a/lib/philomena_web/controllers/duplicate_report/accept_controller.ex +++ b/lib/philomena_web/controllers/duplicate_report/accept_controller.ex @@ -21,12 +21,12 @@ defmodule PhilomenaWeb.DuplicateReport.AcceptController do conn |> put_flash(:info, "Successfully accepted report.") |> moderation_log(details: &log_details/3, data: report.duplicate_report) - |> redirect(to: Routes.duplicate_report_path(conn, :index)) + |> redirect(to: ~p"/duplicate_reports") _error -> conn |> put_flash(:error, "Failed to accept report! Maybe someone else already accepted it.") - |> redirect(to: Routes.duplicate_report_path(conn, :index)) + |> redirect(to: ~p"/duplicate_reports") end end @@ -34,7 +34,7 @@ defmodule PhilomenaWeb.DuplicateReport.AcceptController do %{ body: "Accepted duplicate report, merged #{report.image.id} into #{report.duplicate_of_image.id}", - subject_path: Routes.image_path(conn, :show, report.image) + subject_path: ~p"/images/#{report.image}" } end end diff --git a/lib/philomena_web/controllers/duplicate_report/accept_reverse_controller.ex b/lib/philomena_web/controllers/duplicate_report/accept_reverse_controller.ex index d112ce27..7c04cc49 100644 --- a/lib/philomena_web/controllers/duplicate_report/accept_reverse_controller.ex +++ b/lib/philomena_web/controllers/duplicate_report/accept_reverse_controller.ex @@ -21,12 +21,12 @@ defmodule PhilomenaWeb.DuplicateReport.AcceptReverseController do conn |> put_flash(:info, "Successfully accepted report in reverse.") |> moderation_log(details: &log_details/3, data: report.duplicate_report) - |> redirect(to: Routes.duplicate_report_path(conn, :index)) + |> redirect(to: ~p"/duplicate_reports") _error -> conn |> put_flash(:error, "Failed to accept report! Maybe someone else already accepted it.") - |> redirect(to: Routes.duplicate_report_path(conn, :index)) + |> redirect(to: ~p"/duplicate_reports") end end @@ -34,7 +34,7 @@ defmodule PhilomenaWeb.DuplicateReport.AcceptReverseController do %{ body: "Reverse-accepted duplicate report, merged #{report.image.id} into #{report.duplicate_of_image.id}", - subject_path: Routes.image_path(conn, :show, report.image) + subject_path: ~p"/images/#{report.image}" } end end diff --git a/lib/philomena_web/controllers/duplicate_report/claim_controller.ex b/lib/philomena_web/controllers/duplicate_report/claim_controller.ex index 31646f56..966eddae 100644 --- a/lib/philomena_web/controllers/duplicate_report/claim_controller.ex +++ b/lib/philomena_web/controllers/duplicate_report/claim_controller.ex @@ -21,7 +21,7 @@ defmodule PhilomenaWeb.DuplicateReport.ClaimController do conn |> put_flash(:info, "Successfully claimed report.") |> moderation_log(details: &log_details/3, data: report) - |> redirect(to: Routes.duplicate_report_path(conn, :index)) + |> redirect(to: ~p"/duplicate_reports") end def delete(conn, _params) do @@ -30,7 +30,7 @@ defmodule PhilomenaWeb.DuplicateReport.ClaimController do conn |> put_flash(:info, "Successfully released report.") |> moderation_log(details: &log_details/3) - |> redirect(to: Routes.duplicate_report_path(conn, :index)) + |> redirect(to: ~p"/duplicate_reports") end defp log_details(conn, action, _) do @@ -42,7 +42,7 @@ defmodule PhilomenaWeb.DuplicateReport.ClaimController do %{ body: body, - subject_path: Routes.duplicate_report_path(conn, :index) + subject_path: ~p"/duplicate_reports" } end end diff --git a/lib/philomena_web/controllers/duplicate_report/reject_controller.ex b/lib/philomena_web/controllers/duplicate_report/reject_controller.ex index e019fb2a..83626c36 100644 --- a/lib/philomena_web/controllers/duplicate_report/reject_controller.ex +++ b/lib/philomena_web/controllers/duplicate_report/reject_controller.ex @@ -22,13 +22,13 @@ defmodule PhilomenaWeb.DuplicateReport.RejectController do conn |> put_flash(:info, "Successfully rejected report.") |> moderation_log(details: &log_details/3, data: report) - |> redirect(to: Routes.duplicate_report_path(conn, :index)) + |> redirect(to: ~p"/duplicate_reports") end defp log_details(conn, _action, report) do %{ body: "Rejected duplicate report (#{report.image.id} -> #{report.duplicate_of_image.id})", - subject_path: Routes.duplicate_report_path(conn, :index) + subject_path: ~p"/duplicate_reports" } end end diff --git a/lib/philomena_web/controllers/duplicate_report_controller.ex b/lib/philomena_web/controllers/duplicate_report_controller.ex index f30539a0..5fd80e38 100644 --- a/lib/philomena_web/controllers/duplicate_report_controller.ex +++ b/lib/philomena_web/controllers/duplicate_report_controller.ex @@ -56,12 +56,12 @@ defmodule PhilomenaWeb.DuplicateReportController do {:ok, duplicate_report} -> conn |> put_flash(:info, "Duplicate report created successfully.") - |> redirect(to: Routes.image_path(conn, :show, duplicate_report.image_id)) + |> redirect(to: ~p"/images/#{duplicate_report.image_id}") {:error, _changeset} -> conn |> put_flash(:error, "Failed to submit duplicate report") - |> redirect(to: Routes.image_path(conn, :show, source)) + |> redirect(to: ~p"/images/#{source}") end end diff --git a/lib/philomena_web/controllers/filter/clear_recent.ex b/lib/philomena_web/controllers/filter/clear_recent.ex index f3aed68d..24f321d3 100644 --- a/lib/philomena_web/controllers/filter/clear_recent.ex +++ b/lib/philomena_web/controllers/filter/clear_recent.ex @@ -10,6 +10,6 @@ defmodule PhilomenaWeb.Filter.ClearRecentController do conn |> put_flash(:info, "Cleared recent filters.") - |> redirect(to: Routes.filter_path(conn, :index)) + |> redirect(to: ~p"/filters") end end diff --git a/lib/philomena_web/controllers/filter/public_controller.ex b/lib/philomena_web/controllers/filter/public_controller.ex index 80e23308..e31a8219 100644 --- a/lib/philomena_web/controllers/filter/public_controller.ex +++ b/lib/philomena_web/controllers/filter/public_controller.ex @@ -12,12 +12,12 @@ defmodule PhilomenaWeb.Filter.PublicController do {:ok, filter} -> conn |> put_flash(:info, "Successfully made filter public.") - |> redirect(to: Routes.filter_path(conn, :show, filter)) + |> redirect(to: ~p"/filters/#{filter}") _error -> conn |> put_flash(:error, "Couldn't make filter public!") - |> redirect(to: Routes.filter_path(conn, :show, conn.assigns.filter)) + |> redirect(to: ~p"/filters/#{conn.assigns.filter}") end end end diff --git a/lib/philomena_web/controllers/filter_controller.ex b/lib/philomena_web/controllers/filter_controller.ex index 86c218f8..9f19415f 100644 --- a/lib/philomena_web/controllers/filter_controller.ex +++ b/lib/philomena_web/controllers/filter_controller.ex @@ -146,7 +146,7 @@ defmodule PhilomenaWeb.FilterController do {:ok, filter} -> conn |> put_flash(:info, "Filter created successfully.") - |> redirect(to: Routes.filter_path(conn, :show, filter)) + |> redirect(to: ~p"/filters/#{filter}") {:error, %Ecto.Changeset{} = changeset} -> render(conn, "new.html", changeset: changeset) @@ -171,7 +171,7 @@ defmodule PhilomenaWeb.FilterController do {:ok, filter} -> conn |> put_flash(:info, "Filter updated successfully.") - |> redirect(to: Routes.filter_path(conn, :show, filter)) + |> redirect(to: ~p"/filters/#{filter}") {:error, %Ecto.Changeset{} = changeset} -> render(conn, "edit.html", filter: filter, changeset: changeset) @@ -185,12 +185,12 @@ defmodule PhilomenaWeb.FilterController do {:ok, _filter} -> conn |> put_flash(:info, "Filter deleted successfully.") - |> redirect(to: Routes.filter_path(conn, :index)) + |> redirect(to: ~p"/filters") _error -> conn |> put_flash(:error, "Filter is still in use, not deleted.") - |> redirect(to: Routes.filter_path(conn, :show, filter)) + |> redirect(to: ~p"/filters/#{filter}") end end end diff --git a/lib/philomena_web/controllers/gallery/report_controller.ex b/lib/philomena_web/controllers/gallery/report_controller.ex index 879fd8fd..3d4b5fd5 100644 --- a/lib/philomena_web/controllers/gallery/report_controller.ex +++ b/lib/philomena_web/controllers/gallery/report_controller.ex @@ -21,7 +21,7 @@ defmodule PhilomenaWeb.Gallery.ReportController do def new(conn, _params) do gallery = conn.assigns.gallery - action = Routes.gallery_report_path(conn, :create, gallery) + action = ~p"/galleries/#{gallery}/reports" changeset = %Report{reportable_type: "Gallery", reportable_id: gallery.id} @@ -39,7 +39,7 @@ defmodule PhilomenaWeb.Gallery.ReportController do def create(conn, params) do gallery = conn.assigns.gallery - action = Routes.gallery_report_path(conn, :create, gallery) + action = ~p"/galleries/#{gallery}/reports" ReportController.create(conn, action, gallery, "Gallery", params) end diff --git a/lib/philomena_web/controllers/gallery_controller.ex b/lib/philomena_web/controllers/gallery_controller.ex index ee19d230..2b298d2c 100644 --- a/lib/philomena_web/controllers/gallery_controller.ex +++ b/lib/philomena_web/controllers/gallery_controller.ex @@ -110,7 +110,7 @@ defmodule PhilomenaWeb.GalleryController do {:ok, gallery} -> conn |> put_flash(:info, "Gallery successfully created.") - |> redirect(to: Routes.gallery_path(conn, :show, gallery)) + |> redirect(to: ~p"/galleries/#{gallery}") {:error, changeset} -> conn @@ -132,7 +132,7 @@ defmodule PhilomenaWeb.GalleryController do {:ok, gallery} -> conn |> put_flash(:info, "Gallery successfully updated.") - |> redirect(to: Routes.gallery_path(conn, :show, gallery)) + |> redirect(to: ~p"/galleries/#{gallery}") {:error, changeset} -> conn @@ -147,7 +147,7 @@ defmodule PhilomenaWeb.GalleryController do conn |> put_flash(:info, "Gallery successfully destroyed.") - |> redirect(to: Routes.gallery_path(conn, :index)) + |> redirect(to: ~p"/galleries") end defp prev_next_page_images(conn, query) do diff --git a/lib/philomena_web/controllers/image/anonymous_controller.ex b/lib/philomena_web/controllers/image/anonymous_controller.ex index d74b1682..1855efc9 100644 --- a/lib/philomena_web/controllers/image/anonymous_controller.ex +++ b/lib/philomena_web/controllers/image/anonymous_controller.ex @@ -23,7 +23,7 @@ defmodule PhilomenaWeb.Image.AnonymousController do conn |> put_flash(:info, "Successfully updated anonymity.") |> moderation_log(details: &log_details/3, data: image) - |> redirect(to: Routes.image_path(conn, :show, image)) + |> redirect(to: ~p"/images/#{image}") end defp verify_authorized(conn, _opts) do @@ -36,7 +36,7 @@ defmodule PhilomenaWeb.Image.AnonymousController do defp log_details(conn, _action, image) do %{ body: "Updated anonymity of image >>#{image.id}", - subject_path: Routes.image_path(conn, :show, image) + subject_path: ~p"/images/#{image}" } end end diff --git a/lib/philomena_web/controllers/image/approve_controller.ex b/lib/philomena_web/controllers/image/approve_controller.ex index 689339f8..1a44cb76 100644 --- a/lib/philomena_web/controllers/image/approve_controller.ex +++ b/lib/philomena_web/controllers/image/approve_controller.ex @@ -15,10 +15,10 @@ defmodule PhilomenaWeb.Image.ApproveController do conn |> put_flash(:info, "Image has been approved.") |> moderation_log(details: &log_details/3, data: image) - |> redirect(to: Routes.admin_approval_path(conn, :index)) + |> redirect(to: ~p"/admin/approvals") end defp log_details(conn, _action, image) do - %{body: "Approved image #{image.id}", subject_path: Routes.image_path(conn, :show, image)} + %{body: "Approved image #{image.id}", subject_path: ~p"/images/#{image}"} end end diff --git a/lib/philomena_web/controllers/image/comment/approve_controller.ex b/lib/philomena_web/controllers/image/comment/approve_controller.ex index 699d0cc2..f6b05ca1 100644 --- a/lib/philomena_web/controllers/image/comment/approve_controller.ex +++ b/lib/philomena_web/controllers/image/comment/approve_controller.ex @@ -23,13 +23,13 @@ defmodule PhilomenaWeb.Image.Comment.ApproveController do conn |> put_flash(:info, "Comment has been approved.") |> moderation_log(details: &log_details/3, data: comment) - |> redirect(to: Routes.image_path(conn, :show, comment.image_id) <> "#comment_#{comment.id}") + |> redirect(to: ~p"/images/#{comment.image_id}" <> "#comment_#{comment.id}") end defp log_details(conn, _action, comment) do %{ body: "Approved comment on image >>#{comment.image_id}", - subject_path: Routes.image_path(conn, :show, comment.image_id) <> "#comment_#{comment.id}" + subject_path: ~p"/images/#{comment.image_id}" <> "#comment_#{comment.id}" } end end diff --git a/lib/philomena_web/controllers/image/comment/delete_controller.ex b/lib/philomena_web/controllers/image/comment/delete_controller.ex index 4527e759..21fc2c1f 100644 --- a/lib/philomena_web/controllers/image/comment/delete_controller.ex +++ b/lib/philomena_web/controllers/image/comment/delete_controller.ex @@ -17,23 +17,19 @@ defmodule PhilomenaWeb.Image.Comment.DeleteController do conn |> put_flash(:info, "Comment successfully destroyed!") |> moderation_log(details: &log_details/3, data: comment) - |> redirect( - to: Routes.image_path(conn, :show, comment.image_id) <> "#comment_#{comment.id}" - ) + |> redirect(to: ~p"/images/#{comment.image_id}" <> "#comment_#{comment.id}") {:error, _changeset} -> conn |> put_flash(:error, "Unable to destroy comment!") - |> redirect( - to: Routes.image_path(conn, :show, comment.image_id) <> "#comment_#{comment.id}" - ) + |> redirect(to: ~p"/images/#{comment.image_id}" <> "#comment_#{comment.id}") end end defp log_details(conn, _action, comment) do %{ body: "Destroyed comment on image >>#{comment.image_id}", - subject_path: Routes.image_path(conn, :show, comment.image_id) <> "#comment_#{comment.id}" + subject_path: ~p"/images/#{comment.image_id}" <> "#comment_#{comment.id}" } end end diff --git a/lib/philomena_web/controllers/image/comment/hide_controller.ex b/lib/philomena_web/controllers/image/comment/hide_controller.ex index 1e55f86d..94241104 100644 --- a/lib/philomena_web/controllers/image/comment/hide_controller.ex +++ b/lib/philomena_web/controllers/image/comment/hide_controller.ex @@ -16,16 +16,12 @@ defmodule PhilomenaWeb.Image.Comment.HideController do conn |> put_flash(:info, "Comment successfully hidden!") |> moderation_log(details: &log_details/3, data: comment) - |> redirect( - to: Routes.image_path(conn, :show, comment.image_id) <> "#comment_#{comment.id}" - ) + |> redirect(to: ~p"/images/#{comment.image_id}" <> "#comment_#{comment.id}") _error -> conn |> put_flash(:error, "Unable to hide comment!") - |> redirect( - to: Routes.image_path(conn, :show, comment.image_id) <> "#comment_#{comment.id}" - ) + |> redirect(to: ~p"/images/#{comment.image_id}" <> "#comment_#{comment.id}") end end @@ -37,16 +33,12 @@ defmodule PhilomenaWeb.Image.Comment.HideController do conn |> put_flash(:info, "Comment successfully unhidden!") |> moderation_log(details: &log_details/3, data: comment) - |> redirect( - to: Routes.image_path(conn, :show, comment.image_id) <> "#comment_#{comment.id}" - ) + |> redirect(to: ~p"/images/#{comment.image_id}" <> "#comment_#{comment.id}") {:error, _changeset} -> conn |> put_flash(:error, "Unable to unhide comment!") - |> redirect( - to: Routes.image_path(conn, :show, comment.image_id) <> "#comment_#{comment.id}" - ) + |> redirect(to: ~p"/images/#{comment.image_id}" <> "#comment_#{comment.id}") end end @@ -59,7 +51,7 @@ defmodule PhilomenaWeb.Image.Comment.HideController do %{ body: body, - subject_path: Routes.image_path(conn, :show, comment.image_id) <> "#comment_#{comment.id}" + subject_path: ~p"/images/#{comment.image_id}" <> "#comment_#{comment.id}" } end end diff --git a/lib/philomena_web/controllers/image/comment/report_controller.ex b/lib/philomena_web/controllers/image/comment/report_controller.ex index 27725a4b..d957abbd 100644 --- a/lib/philomena_web/controllers/image/comment/report_controller.ex +++ b/lib/philomena_web/controllers/image/comment/report_controller.ex @@ -24,7 +24,7 @@ defmodule PhilomenaWeb.Image.Comment.ReportController do def new(conn, _params) do comment = conn.assigns.comment - action = Routes.image_comment_report_path(conn, :create, comment.image, comment) + action = ~p"/images/#{comment.image}/comments/#{comment}/reports" changeset = %Report{reportable_type: "Comment", reportable_id: comment.id} @@ -42,7 +42,7 @@ defmodule PhilomenaWeb.Image.Comment.ReportController do def create(conn, params) do comment = conn.assigns.comment - action = Routes.image_comment_report_path(conn, :create, comment.image, comment) + action = ~p"/images/#{comment.image}/comments/#{comment}/reports" ReportController.create(conn, action, comment, "Comment", params) end diff --git a/lib/philomena_web/controllers/image/comment_controller.ex b/lib/philomena_web/controllers/image/comment_controller.ex index cfcda777..ca0ff9ad 100644 --- a/lib/philomena_web/controllers/image/comment_controller.ex +++ b/lib/philomena_web/controllers/image/comment_controller.ex @@ -42,7 +42,7 @@ defmodule PhilomenaWeb.Image.CommentController do def index(conn, %{"comment_id" => comment_id}) do page = CommentLoader.find_page(conn, conn.assigns.image, comment_id) - redirect(conn, to: Routes.image_comment_path(conn, :index, conn.assigns.image, page: page)) + redirect(conn, to: ~p"/images/#{conn.assigns.image}/comments?#{[page: page]}") end def index(conn, _params) do @@ -93,7 +93,7 @@ defmodule PhilomenaWeb.Image.CommentController do _error -> conn |> put_flash(:error, "There was an error posting your comment") - |> redirect(to: Routes.image_path(conn, :show, image)) + |> redirect(to: ~p"/images/#{image}") end end @@ -126,9 +126,7 @@ defmodule PhilomenaWeb.Image.CommentController do conn |> put_flash(:info, "Comment updated successfully.") - |> redirect( - to: Routes.image_path(conn, :show, conn.assigns.image) <> "#comment_#{comment.id}" - ) + |> redirect(to: ~p"/images/#{conn.assigns.image}" <> "#comment_#{comment.id}") {:error, :comment, changeset, _changes} -> render(conn, "edit.html", comment: conn.assigns.comment, changeset: changeset) diff --git a/lib/philomena_web/controllers/image/comment_lock_controller.ex b/lib/philomena_web/controllers/image/comment_lock_controller.ex index e913bdb6..c6c5b2b9 100644 --- a/lib/philomena_web/controllers/image/comment_lock_controller.ex +++ b/lib/philomena_web/controllers/image/comment_lock_controller.ex @@ -13,7 +13,7 @@ defmodule PhilomenaWeb.Image.CommentLockController do conn |> put_flash(:info, "Successfully locked comments.") |> moderation_log(details: &log_details/3, data: image) - |> redirect(to: Routes.image_path(conn, :show, image)) + |> redirect(to: ~p"/images/#{image}") end def delete(conn, _params) do @@ -22,7 +22,7 @@ defmodule PhilomenaWeb.Image.CommentLockController do conn |> put_flash(:info, "Successfully unlocked comments.") |> moderation_log(details: &log_details/3, data: image) - |> redirect(to: Routes.image_path(conn, :show, image)) + |> redirect(to: ~p"/images/#{image}") end defp log_details(conn, action, image) do @@ -34,7 +34,7 @@ defmodule PhilomenaWeb.Image.CommentLockController do %{ body: body, - subject_path: Routes.image_path(conn, :show, image) + subject_path: ~p"/images/#{image}" } end end diff --git a/lib/philomena_web/controllers/image/delete_controller.ex b/lib/philomena_web/controllers/image/delete_controller.ex index adae818c..3d86cfa6 100644 --- a/lib/philomena_web/controllers/image/delete_controller.ex +++ b/lib/philomena_web/controllers/image/delete_controller.ex @@ -20,12 +20,12 @@ defmodule PhilomenaWeb.Image.DeleteController do conn |> put_flash(:info, "Image successfully hidden.") |> moderation_log(details: &log_details/3, data: result.image) - |> redirect(to: Routes.image_path(conn, :show, image)) + |> redirect(to: ~p"/images/#{image}") _error -> conn |> put_flash(:error, "Failed to hide image.") - |> redirect(to: Routes.image_path(conn, :show, image)) + |> redirect(to: ~p"/images/#{image}") end end @@ -37,12 +37,12 @@ defmodule PhilomenaWeb.Image.DeleteController do conn |> put_flash(:info, "Hide reason updated.") |> moderation_log(details: &log_details/3, data: image) - |> redirect(to: Routes.image_path(conn, :show, image)) + |> redirect(to: ~p"/images/#{image}") {:error, _changeset} -> conn |> put_flash(:error, "Couldn't update hide reason.") - |> redirect(to: Routes.image_path(conn, :show, image)) + |> redirect(to: ~p"/images/#{image}") end end @@ -54,7 +54,7 @@ defmodule PhilomenaWeb.Image.DeleteController do _false -> conn |> put_flash(:error, "Cannot change hide reason on a non-hidden image!") - |> redirect(to: Routes.image_path(conn, :show, conn.assigns.image)) + |> redirect(to: ~p"/images/#{conn.assigns.image}") |> halt() end end @@ -67,7 +67,7 @@ defmodule PhilomenaWeb.Image.DeleteController do conn |> put_flash(:info, "Image successfully unhidden.") |> moderation_log(details: &log_details/3, data: image) - |> redirect(to: Routes.image_path(conn, :show, image)) + |> redirect(to: ~p"/images/#{image}") end defp log_details(conn, action, image) do @@ -80,7 +80,7 @@ defmodule PhilomenaWeb.Image.DeleteController do %{ body: body, - subject_path: Routes.image_path(conn, :show, image) + subject_path: ~p"/images/#{image}" } end end diff --git a/lib/philomena_web/controllers/image/description_lock_controller.ex b/lib/philomena_web/controllers/image/description_lock_controller.ex index ed8c9c87..bde327ac 100644 --- a/lib/philomena_web/controllers/image/description_lock_controller.ex +++ b/lib/philomena_web/controllers/image/description_lock_controller.ex @@ -13,7 +13,7 @@ defmodule PhilomenaWeb.Image.DescriptionLockController do conn |> put_flash(:info, "Successfully locked description.") |> moderation_log(details: &log_details/3, data: image) - |> redirect(to: Routes.image_path(conn, :show, image)) + |> redirect(to: ~p"/images/#{image}") end def delete(conn, _params) do @@ -22,7 +22,7 @@ defmodule PhilomenaWeb.Image.DescriptionLockController do conn |> put_flash(:info, "Successfully unlocked description.") |> moderation_log(details: &log_details/3, data: image) - |> redirect(to: Routes.image_path(conn, :show, image)) + |> redirect(to: ~p"/images/#{image}") end defp log_details(conn, action, image) do @@ -34,7 +34,7 @@ defmodule PhilomenaWeb.Image.DescriptionLockController do %{ body: body, - subject_path: Routes.image_path(conn, :show, image) + subject_path: ~p"/images/#{image}" } end end diff --git a/lib/philomena_web/controllers/image/destroy_controller.ex b/lib/philomena_web/controllers/image/destroy_controller.ex index fe2f3e6e..8f4ed867 100644 --- a/lib/philomena_web/controllers/image/destroy_controller.ex +++ b/lib/philomena_web/controllers/image/destroy_controller.ex @@ -16,12 +16,12 @@ defmodule PhilomenaWeb.Image.DestroyController do conn |> put_flash(:info, "Image contents destroyed.") |> moderation_log(details: &log_details/3, data: image) - |> redirect(to: Routes.image_path(conn, :show, image)) + |> redirect(to: ~p"/images/#{image}") _error -> conn |> put_flash(:error, "Failed to destroy image.") - |> redirect(to: Routes.image_path(conn, :show, image)) + |> redirect(to: ~p"/images/#{image}") end end @@ -33,7 +33,7 @@ defmodule PhilomenaWeb.Image.DestroyController do _false -> conn |> put_flash(:error, "Cannot destroy a non-hidden image!") - |> redirect(to: Routes.image_path(conn, :show, conn.assigns.image)) + |> redirect(to: ~p"/images/#{conn.assigns.image}") |> halt() end end @@ -41,7 +41,7 @@ defmodule PhilomenaWeb.Image.DestroyController do defp log_details(conn, _action, image) do %{ body: "Hard-deleted image >>#{image.id}", - subject_path: Routes.image_path(conn, :show, image) + subject_path: ~p"/images/#{image}" } end end diff --git a/lib/philomena_web/controllers/image/feature_controller.ex b/lib/philomena_web/controllers/image/feature_controller.ex index a16ee809..74c19c05 100644 --- a/lib/philomena_web/controllers/image/feature_controller.ex +++ b/lib/philomena_web/controllers/image/feature_controller.ex @@ -17,7 +17,7 @@ defmodule PhilomenaWeb.Image.FeatureController do conn |> put_flash(:info, "Image marked as featured image.") |> moderation_log(details: &log_details/3, data: image) - |> redirect(to: Routes.image_path(conn, :show, image)) + |> redirect(to: ~p"/images/#{image}") end defp verify_not_deleted(conn, _opts) do @@ -25,7 +25,7 @@ defmodule PhilomenaWeb.Image.FeatureController do true -> conn |> put_flash(:error, "Cannot feature a hidden image.") - |> redirect(to: Routes.image_path(conn, :show, conn.assigns.image)) + |> redirect(to: ~p"/images/#{conn.assigns.image}") |> halt() _false -> @@ -36,7 +36,7 @@ defmodule PhilomenaWeb.Image.FeatureController do defp log_details(conn, _action, image) do %{ body: "Featured image >>#{image.id}", - subject_path: Routes.image_path(conn, :show, image) + subject_path: ~p"/images/#{image}" } end end diff --git a/lib/philomena_web/controllers/image/file_controller.ex b/lib/philomena_web/controllers/image/file_controller.ex index 8b3f0e3f..f169d2f4 100644 --- a/lib/philomena_web/controllers/image/file_controller.ex +++ b/lib/philomena_web/controllers/image/file_controller.ex @@ -16,12 +16,12 @@ defmodule PhilomenaWeb.Image.FileController do {:ok, image} -> conn |> put_flash(:info, "Successfully updated file.") - |> redirect(to: Routes.image_path(conn, :show, image)) + |> redirect(to: ~p"/images/#{image}") _error -> conn |> put_flash(:error, "Failed to update file!") - |> redirect(to: Routes.image_path(conn, :show, conn.assigns.image)) + |> redirect(to: ~p"/images/#{conn.assigns.image}") end end @@ -30,7 +30,7 @@ defmodule PhilomenaWeb.Image.FileController do true -> conn |> put_flash(:error, "Cannot replace a hidden image.") - |> redirect(to: Routes.image_path(conn, :show, conn.assigns.image)) + |> redirect(to: ~p"/images/#{conn.assigns.image}") |> halt() _false -> diff --git a/lib/philomena_web/controllers/image/hash_controller.ex b/lib/philomena_web/controllers/image/hash_controller.ex index ad99b133..233d5202 100644 --- a/lib/philomena_web/controllers/image/hash_controller.ex +++ b/lib/philomena_web/controllers/image/hash_controller.ex @@ -13,13 +13,13 @@ defmodule PhilomenaWeb.Image.HashController do conn |> put_flash(:info, "Successfully cleared hash.") |> moderation_log(details: &log_details/3, data: image) - |> redirect(to: Routes.image_path(conn, :show, image)) + |> redirect(to: ~p"/images/#{image}") end defp log_details(conn, _action, image) do %{ body: "Cleared hash of image >>#{image.id}", - subject_path: Routes.image_path(conn, :show, image) + subject_path: ~p"/images/#{image}" } end end diff --git a/lib/philomena_web/controllers/image/navigate_controller.ex b/lib/philomena_web/controllers/image/navigate_controller.ex index ab74f038..c0827caa 100644 --- a/lib/philomena_web/controllers/image/navigate_controller.ex +++ b/lib/philomena_web/controllers/image/navigate_controller.ex @@ -21,11 +21,11 @@ defmodule PhilomenaWeb.Image.NavigateController do |> case do {next_image, hit} -> redirect(conn, - to: Routes.image_path(conn, :show, next_image, Keyword.put(scope, :sort, hit["sort"])) + to: ~p"/images/#{next_image}?#{Keyword.put(scope, :sort, hit["sort"])}" ) nil -> - redirect(conn, to: Routes.image_path(conn, :show, image, scope)) + redirect(conn, to: ~p"/images/#{image}?#{scope}") end end @@ -41,7 +41,7 @@ defmodule PhilomenaWeb.Image.NavigateController do page_num = page_for_offset(pagination.page_size, images.total_entries) - redirect(conn, to: Routes.search_path(conn, :index, q: "*", page: page_num)) + redirect(conn, to: ~p"/search?#{[q: "*", page: page_num]}") end defp page_for_offset(per_page, offset) do diff --git a/lib/philomena_web/controllers/image/random_controller.ex b/lib/philomena_web/controllers/image/random_controller.ex index f39d8c75..9bc293f7 100644 --- a/lib/philomena_web/controllers/image/random_controller.ex +++ b/lib/philomena_web/controllers/image/random_controller.ex @@ -20,10 +20,10 @@ defmodule PhilomenaWeb.Image.RandomController do case unwrap_random_result(search_definition) do nil -> - redirect(conn, to: Routes.image_path(conn, :index)) + redirect(conn, to: ~p"/images") random_id -> - redirect(conn, to: Routes.image_path(conn, :show, random_id, scope)) + redirect(conn, to: ~p"/images/#{random_id}?#{scope}") end end diff --git a/lib/philomena_web/controllers/image/repair_controller.ex b/lib/philomena_web/controllers/image/repair_controller.ex index 7e40835a..10d86773 100644 --- a/lib/philomena_web/controllers/image/repair_controller.ex +++ b/lib/philomena_web/controllers/image/repair_controller.ex @@ -14,13 +14,13 @@ defmodule PhilomenaWeb.Image.RepairController do conn |> put_flash(:info, "Repair job enqueued.") |> moderation_log(details: &log_details/3, data: conn.assigns.image) - |> redirect(to: Routes.image_path(conn, :show, conn.assigns.image)) + |> redirect(to: ~p"/images/#{conn.assigns.image}") end defp log_details(conn, _action, image) do %{ body: "Repaired image >>#{image.id}", - subject_path: Routes.image_path(conn, :show, image) + subject_path: ~p"/images/#{image}" } end end diff --git a/lib/philomena_web/controllers/image/report_controller.ex b/lib/philomena_web/controllers/image/report_controller.ex index 99e2bace..6956832e 100644 --- a/lib/philomena_web/controllers/image/report_controller.ex +++ b/lib/philomena_web/controllers/image/report_controller.ex @@ -21,7 +21,7 @@ defmodule PhilomenaWeb.Image.ReportController do def new(conn, _params) do image = conn.assigns.image - action = Routes.image_report_path(conn, :create, image) + action = ~p"/images/#{image}/reports" changeset = %Report{reportable_type: "Image", reportable_id: image.id} @@ -39,7 +39,7 @@ defmodule PhilomenaWeb.Image.ReportController do def create(conn, params) do image = conn.assigns.image - action = Routes.image_report_path(conn, :create, image) + action = ~p"/images/#{image}/reports" ReportController.create(conn, action, image, "Image", params) end diff --git a/lib/philomena_web/controllers/image/scratchpad_controller.ex b/lib/philomena_web/controllers/image/scratchpad_controller.ex index 863c0bc8..4fddb135 100644 --- a/lib/philomena_web/controllers/image/scratchpad_controller.ex +++ b/lib/philomena_web/controllers/image/scratchpad_controller.ex @@ -18,13 +18,13 @@ defmodule PhilomenaWeb.Image.ScratchpadController do conn |> put_flash(:info, "Successfully updated moderation notes.") |> moderation_log(details: &log_details/3, data: image) - |> redirect(to: Routes.image_path(conn, :show, image)) + |> redirect(to: ~p"/images/#{image}") end defp log_details(conn, _action, image) do %{ body: "Updated mod notes on image >>#{image.id} (#{image.scratchpad})", - subject_path: Routes.image_path(conn, :show, image) + subject_path: ~p"/images/#{image}" } end end diff --git a/lib/philomena_web/controllers/image/source_history_controller.ex b/lib/philomena_web/controllers/image/source_history_controller.ex index 24bab27f..85f061db 100644 --- a/lib/philomena_web/controllers/image/source_history_controller.ex +++ b/lib/philomena_web/controllers/image/source_history_controller.ex @@ -15,13 +15,13 @@ defmodule PhilomenaWeb.Image.SourceHistoryController do conn |> put_flash(:info, "Successfully deleted source history.") |> moderation_log(details: &log_details/3, data: image) - |> redirect(to: Routes.image_path(conn, :show, image)) + |> redirect(to: ~p"/images/#{image}") end defp log_details(conn, _action, image) do %{ body: "Deleted source history for image >>#{image.id}", - subject_path: Routes.image_path(conn, :show, image) + subject_path: ~p"/images/#{image}" } end end diff --git a/lib/philomena_web/controllers/image/tag_change_controller.ex b/lib/philomena_web/controllers/image/tag_change_controller.ex index 6868ed96..b2716558 100644 --- a/lib/philomena_web/controllers/image/tag_change_controller.ex +++ b/lib/philomena_web/controllers/image/tag_change_controller.ex @@ -46,7 +46,7 @@ defmodule PhilomenaWeb.Image.TagChangeController do details: &log_details/3, data: %{image: image, details: tag_change_details(tag_change)} ) - |> redirect(to: Routes.image_path(conn, :show, image)) + |> redirect(to: ~p"/images/#{image}") end defp added_filter(query, %{"added" => "1"}), @@ -61,7 +61,7 @@ defmodule PhilomenaWeb.Image.TagChangeController do defp log_details(conn, _action, %{image: image, details: details}) do %{ body: "Deleted tag change #{details} on >>#{image.id} from history", - subject_path: Routes.image_path(conn, :show, image) + subject_path: ~p"/images/#{image}" } end diff --git a/lib/philomena_web/controllers/image/tag_lock_controller.ex b/lib/philomena_web/controllers/image/tag_lock_controller.ex index 2f71b4a3..4e6a0e70 100644 --- a/lib/philomena_web/controllers/image/tag_lock_controller.ex +++ b/lib/philomena_web/controllers/image/tag_lock_controller.ex @@ -24,7 +24,7 @@ defmodule PhilomenaWeb.Image.TagLockController do conn |> put_flash(:info, "Successfully updated list of locked tags.") |> moderation_log(details: &log_details/3, data: image) - |> redirect(to: Routes.image_path(conn, :show, image)) + |> redirect(to: ~p"/images/#{image}") end def create(conn, _params) do @@ -33,7 +33,7 @@ defmodule PhilomenaWeb.Image.TagLockController do conn |> put_flash(:info, "Successfully locked tags.") |> moderation_log(details: &log_details/3, data: image) - |> redirect(to: Routes.image_path(conn, :show, image)) + |> redirect(to: ~p"/images/#{image}") end def delete(conn, _params) do @@ -42,7 +42,7 @@ defmodule PhilomenaWeb.Image.TagLockController do conn |> put_flash(:info, "Successfully unlocked tags.") |> moderation_log(details: &log_details/3, data: image) - |> redirect(to: Routes.image_path(conn, :show, image)) + |> redirect(to: ~p"/images/#{image}") end defp log_details(conn, action, image) do @@ -55,7 +55,7 @@ defmodule PhilomenaWeb.Image.TagLockController do %{ body: body, - subject_path: Routes.image_path(conn, :show, image) + subject_path: ~p"/images/#{image}" } end end diff --git a/lib/philomena_web/controllers/image/tamper_controller.ex b/lib/philomena_web/controllers/image/tamper_controller.ex index 8eb66309..4ce1ac3c 100644 --- a/lib/philomena_web/controllers/image/tamper_controller.ex +++ b/lib/philomena_web/controllers/image/tamper_controller.ex @@ -28,7 +28,7 @@ defmodule PhilomenaWeb.Image.TamperController do details: &log_details/3, data: %{vote: result, image: image} ) - |> redirect(to: Routes.image_path(conn, :show, conn.assigns.image)) + |> redirect(to: ~p"/images/#{conn.assigns.image}") end defp log_details(conn, _action, data) do @@ -43,7 +43,7 @@ defmodule PhilomenaWeb.Image.TamperController do %{ body: "Deleted #{vote_type} by #{conn.assigns.user.name} on image >>#{data.image.id}", - subject_path: Routes.image_path(conn, :show, image) + subject_path: ~p"/images/#{image}" } end end diff --git a/lib/philomena_web/controllers/image_controller.ex b/lib/philomena_web/controllers/image_controller.ex index 47e9e088..30364cda 100644 --- a/lib/philomena_web/controllers/image_controller.ex +++ b/lib/philomena_web/controllers/image_controller.ex @@ -128,7 +128,7 @@ defmodule PhilomenaWeb.ImageController do conn |> put_flash(:info, "Image created successfully.") - |> redirect(to: Routes.image_path(conn, :show, image)) + |> redirect(to: ~p"/images/#{image}") {:error, :image, changeset, _} -> conn @@ -208,7 +208,7 @@ defmodule PhilomenaWeb.ImageController do :info, "The image you were looking for has been marked a duplicate of the image below" ) - |> redirect(to: Routes.image_path(conn, :show, image.duplicate_id)) + |> redirect(to: ~p"/images/#{image.duplicate_id}") |> halt() true -> diff --git a/lib/philomena_web/controllers/page_controller.ex b/lib/philomena_web/controllers/page_controller.ex index 1f8490a2..d9ebae27 100644 --- a/lib/philomena_web/controllers/page_controller.ex +++ b/lib/philomena_web/controllers/page_controller.ex @@ -26,7 +26,7 @@ defmodule PhilomenaWeb.PageController do {:ok, %{static_page: static_page}} -> conn |> put_flash(:info, "Static page successfully created.") - |> redirect(to: Routes.page_path(conn, :show, static_page)) + |> redirect(to: ~p"/pages/#{static_page}") {:error, :static_page, changeset, _changes} -> render(conn, "new.html", changeset: changeset) @@ -47,7 +47,7 @@ defmodule PhilomenaWeb.PageController do {:ok, %{static_page: static_page}} -> conn |> put_flash(:info, "Static page successfully updated.") - |> redirect(to: Routes.page_path(conn, :show, static_page)) + |> redirect(to: ~p"/pages/#{static_page}") {:error, :static_page, changeset, _changes} -> render(conn, "edit.html", changeset: changeset) diff --git a/lib/philomena_web/controllers/password_controller.ex b/lib/philomena_web/controllers/password_controller.ex index 4a0a7bb1..597f0af0 100644 --- a/lib/philomena_web/controllers/password_controller.ex +++ b/lib/philomena_web/controllers/password_controller.ex @@ -16,7 +16,7 @@ defmodule PhilomenaWeb.PasswordController do if user = Users.get_user_by_email(email) do Users.deliver_user_reset_password_instructions( user, - &Routes.password_url(conn, :edit, &1) + &url(~p"/passwords/#{&1}/edit") ) end @@ -40,7 +40,7 @@ defmodule PhilomenaWeb.PasswordController do {:ok, _} -> conn |> put_flash(:info, "Password reset successfully.") - |> redirect(to: Routes.session_path(conn, :new)) + |> redirect(to: ~p"/sessions/new") {:error, changeset} -> render(conn, "edit.html", changeset: changeset) diff --git a/lib/philomena_web/controllers/profile/artist_link_controller.ex b/lib/philomena_web/controllers/profile/artist_link_controller.ex index 3d48c308..6362a1b7 100644 --- a/lib/philomena_web/controllers/profile/artist_link_controller.ex +++ b/lib/philomena_web/controllers/profile/artist_link_controller.ex @@ -52,9 +52,7 @@ defmodule PhilomenaWeb.Profile.ArtistLinkController do :info, "Link submitted! Please put '#{artist_link.verification_code}' on your linked webpage now." ) - |> redirect( - to: Routes.profile_artist_link_path(conn, :show, conn.assigns.user, artist_link) - ) + |> redirect(to: ~p"/profiles/#{conn.assigns.user}/artist_links/#{artist_link}") {:error, %Ecto.Changeset{} = changeset} -> render(conn, "new.html", changeset: changeset) @@ -77,9 +75,7 @@ defmodule PhilomenaWeb.Profile.ArtistLinkController do {:ok, artist_link} -> conn |> put_flash(:info, "Link successfully updated.") - |> redirect( - to: Routes.profile_artist_link_path(conn, :show, conn.assigns.user, artist_link) - ) + |> redirect(to: ~p"/profiles/#{conn.assigns.user}/artist_links/#{artist_link}") {:error, changeset} -> render(conn, "edit.html", changeset: changeset) diff --git a/lib/philomena_web/controllers/profile/award_controller.ex b/lib/philomena_web/controllers/profile/award_controller.ex index 07df9819..4e636236 100644 --- a/lib/philomena_web/controllers/profile/award_controller.ex +++ b/lib/philomena_web/controllers/profile/award_controller.ex @@ -23,7 +23,7 @@ defmodule PhilomenaWeb.Profile.AwardController do {:ok, _award} -> conn |> put_flash(:info, "Award successfully created.") - |> redirect(to: Routes.profile_path(conn, :show, conn.assigns.user)) + |> redirect(to: ~p"/profiles/#{conn.assigns.user}") {:error, changeset} -> render(conn, "new.html", changeset: changeset) @@ -40,7 +40,7 @@ defmodule PhilomenaWeb.Profile.AwardController do {:ok, _award} -> conn |> put_flash(:info, "Award successfully updated.") - |> redirect(to: Routes.profile_path(conn, :show, conn.assigns.user)) + |> redirect(to: ~p"/profiles/#{conn.assigns.user}") {:error, changeset} -> render(conn, "edit.html", changeset: changeset) @@ -52,7 +52,7 @@ defmodule PhilomenaWeb.Profile.AwardController do conn |> put_flash(:info, "Award successfully destroyed. By cruel and unusual means.") - |> redirect(to: Routes.profile_path(conn, :show, conn.assigns.user)) + |> redirect(to: ~p"/profiles/#{conn.assigns.user}") end defp verify_authorized(conn, _opts) do diff --git a/lib/philomena_web/controllers/profile/commission/item_controller.ex b/lib/philomena_web/controllers/profile/commission/item_controller.ex index 90699b08..11cc0ab6 100644 --- a/lib/philomena_web/controllers/profile/commission/item_controller.ex +++ b/lib/philomena_web/controllers/profile/commission/item_controller.ex @@ -47,7 +47,7 @@ defmodule PhilomenaWeb.Profile.Commission.ItemController do {:ok, _multi} -> conn |> put_flash(:info, "Item successfully created.") - |> redirect(to: Routes.profile_commission_path(conn, :show, conn.assigns.user)) + |> redirect(to: ~p"/profiles/#{conn.assigns.user}/commission") {:error, changeset} -> render(conn, "new.html", user: user, commission: commission, changeset: changeset) @@ -79,7 +79,7 @@ defmodule PhilomenaWeb.Profile.Commission.ItemController do {:ok, _commission} -> conn |> put_flash(:info, "Item successfully updated.") - |> redirect(to: Routes.profile_commission_path(conn, :show, conn.assigns.user)) + |> redirect(to: ~p"/profiles/#{conn.assigns.user}/commission") {:error, changeset} -> render(conn, "edit.html", @@ -100,7 +100,7 @@ defmodule PhilomenaWeb.Profile.Commission.ItemController do conn |> put_flash(:info, "Item deleted successfully.") - |> redirect(to: Routes.profile_commission_path(conn, :show, conn.assigns.user)) + |> redirect(to: ~p"/profiles/#{conn.assigns.user}/commission") end defp ensure_commission(conn, _opts) do diff --git a/lib/philomena_web/controllers/profile/commission/report_controller.ex b/lib/philomena_web/controllers/profile/commission/report_controller.ex index 9c9d7ac2..0ad943ef 100644 --- a/lib/philomena_web/controllers/profile/commission/report_controller.ex +++ b/lib/philomena_web/controllers/profile/commission/report_controller.ex @@ -32,7 +32,7 @@ defmodule PhilomenaWeb.Profile.Commission.ReportController do def new(conn, _params) do user = conn.assigns.user commission = conn.assigns.user.commission - action = Routes.profile_commission_report_path(conn, :create, user) + action = ~p"/profiles/#{user}/commission/reports" changeset = %Report{reportable_type: "Commission", reportable_id: commission.id} @@ -51,7 +51,7 @@ defmodule PhilomenaWeb.Profile.Commission.ReportController do def create(conn, params) do user = conn.assigns.user commission = conn.assigns.user.commission - action = Routes.profile_commission_report_path(conn, :create, user) + action = ~p"/profiles/#{user}/commission/reports" ReportController.create(conn, action, commission, "Commission", params) end diff --git a/lib/philomena_web/controllers/profile/commission_controller.ex b/lib/philomena_web/controllers/profile/commission_controller.ex index f934fc4d..7cd2b844 100644 --- a/lib/philomena_web/controllers/profile/commission_controller.ex +++ b/lib/philomena_web/controllers/profile/commission_controller.ex @@ -85,7 +85,7 @@ defmodule PhilomenaWeb.Profile.CommissionController do {:ok, _commission} -> conn |> put_flash(:info, "Commission successfully created.") - |> redirect(to: Routes.profile_commission_path(conn, :show, user)) + |> redirect(to: ~p"/profiles/#{user}/commission") {:error, changeset} -> render(conn, "new.html", changeset: changeset) @@ -104,7 +104,7 @@ defmodule PhilomenaWeb.Profile.CommissionController do {:ok, _commission} -> conn |> put_flash(:info, "Commission successfully updated.") - |> redirect(to: Routes.profile_commission_path(conn, :show, conn.assigns.user)) + |> redirect(to: ~p"/profiles/#{conn.assigns.user}/commission") {:error, changeset} -> render(conn, "edit.html", changeset: changeset) @@ -118,7 +118,7 @@ defmodule PhilomenaWeb.Profile.CommissionController do conn |> put_flash(:info, "Commission deleted successfully.") - |> redirect(to: Routes.commission_path(conn, :index)) + |> redirect(to: ~p"/commissions") end defp ensure_commission(conn, _opts) do @@ -156,7 +156,7 @@ defmodule PhilomenaWeb.Profile.CommissionController do :error, "You must have a verified artist link to create a commission listing." ) - |> redirect(to: Routes.commission_path(conn, :index)) + |> redirect(to: ~p"/commissions") |> halt() end end diff --git a/lib/philomena_web/controllers/profile/description_controller.ex b/lib/philomena_web/controllers/profile/description_controller.ex index 4a7836ba..6dac8e88 100644 --- a/lib/philomena_web/controllers/profile/description_controller.ex +++ b/lib/philomena_web/controllers/profile/description_controller.ex @@ -30,7 +30,7 @@ defmodule PhilomenaWeb.Profile.DescriptionController do {:ok, _user} -> conn |> put_flash(:info, "Description successfully updated.") - |> redirect(to: Routes.profile_path(conn, :show, user)) + |> redirect(to: ~p"/profiles/#{user}") {:error, changeset} -> render(conn, "edit.html", changeset: changeset) diff --git a/lib/philomena_web/controllers/profile/report_controller.ex b/lib/philomena_web/controllers/profile/report_controller.ex index 0c326b8d..80a68895 100644 --- a/lib/philomena_web/controllers/profile/report_controller.ex +++ b/lib/philomena_web/controllers/profile/report_controller.ex @@ -21,7 +21,7 @@ defmodule PhilomenaWeb.Profile.ReportController do def new(conn, _params) do user = conn.assigns.user - action = Routes.profile_report_path(conn, :create, user) + action = ~p"/profiles/#{user}/reports" changeset = %Report{reportable_type: "User", reportable_id: user.id} @@ -39,7 +39,7 @@ defmodule PhilomenaWeb.Profile.ReportController do def create(conn, params) do user = conn.assigns.user - action = Routes.profile_report_path(conn, :create, user) + action = ~p"/profiles/#{user}/reports" ReportController.create(conn, action, user, "User", params) end diff --git a/lib/philomena_web/controllers/profile/scratchpad_controller.ex b/lib/philomena_web/controllers/profile/scratchpad_controller.ex index 117fb3b6..3132436e 100644 --- a/lib/philomena_web/controllers/profile/scratchpad_controller.ex +++ b/lib/philomena_web/controllers/profile/scratchpad_controller.ex @@ -25,7 +25,7 @@ defmodule PhilomenaWeb.Profile.ScratchpadController do {:ok, _user} -> conn |> put_flash(:info, "Moderation scratchpad successfully updated.") - |> redirect(to: Routes.profile_path(conn, :show, user)) + |> redirect(to: ~p"/profiles/#{user}") {:error, changeset} -> render(conn, "edit.html", changeset: changeset) diff --git a/lib/philomena_web/controllers/registration/email_controller.ex b/lib/philomena_web/controllers/registration/email_controller.ex index e20a9bb0..0c696906 100644 --- a/lib/philomena_web/controllers/registration/email_controller.ex +++ b/lib/philomena_web/controllers/registration/email_controller.ex @@ -11,7 +11,7 @@ defmodule PhilomenaWeb.Registration.EmailController do Users.deliver_update_email_instructions( applied_user, user.email, - &Routes.registration_email_url(conn, :show, &1) + &url(~p"/registrations/email/#{&1}") ) conn @@ -19,12 +19,12 @@ defmodule PhilomenaWeb.Registration.EmailController do :info, "A link to confirm your email change has been sent to the new address." ) - |> redirect(to: Routes.registration_path(conn, :edit)) + |> redirect(to: ~p"/registrations/edit") {:error, _changeset} -> conn |> put_flash(:error, "Failed to update email.") - |> redirect(to: Routes.registration_path(conn, :edit)) + |> redirect(to: ~p"/registrations/edit") end end @@ -33,12 +33,12 @@ defmodule PhilomenaWeb.Registration.EmailController do :ok -> conn |> put_flash(:info, "Email changed successfully.") - |> redirect(to: Routes.registration_path(conn, :edit)) + |> redirect(to: ~p"/registrations/edit") :error -> conn |> put_flash(:error, "Email change link is invalid or it has expired.") - |> redirect(to: Routes.registration_path(conn, :edit)) + |> redirect(to: ~p"/registrations/edit") end end end diff --git a/lib/philomena_web/controllers/registration/name_controller.ex b/lib/philomena_web/controllers/registration/name_controller.ex index 7b5cd0dd..e0023f89 100644 --- a/lib/philomena_web/controllers/registration/name_controller.ex +++ b/lib/philomena_web/controllers/registration/name_controller.ex @@ -17,7 +17,7 @@ defmodule PhilomenaWeb.Registration.NameController do {:ok, user} -> conn |> put_flash(:info, "Name successfully updated.") - |> redirect(to: Routes.profile_path(conn, :show, user)) + |> redirect(to: ~p"/profiles/#{user}") {:error, changeset} -> render(conn, "edit.html", changeset: changeset) diff --git a/lib/philomena_web/controllers/registration/password_controller.ex b/lib/philomena_web/controllers/registration/password_controller.ex index 909df6eb..6e3ba04a 100644 --- a/lib/philomena_web/controllers/registration/password_controller.ex +++ b/lib/philomena_web/controllers/registration/password_controller.ex @@ -13,13 +13,13 @@ defmodule PhilomenaWeb.Registration.PasswordController do {:ok, user} -> conn |> put_flash(:info, "Password updated successfully.") - |> put_session(:user_return_to, Routes.registration_path(conn, :edit)) + |> put_session(:user_return_to, ~p"/registrations/edit") |> UserAuth.log_in_user(user) {:error, _changeset} -> conn |> put_flash(:error, "Failed to update password.") - |> redirect(to: Routes.registration_path(conn, :edit)) + |> redirect(to: ~p"/registrations/edit") end end end diff --git a/lib/philomena_web/controllers/registration/totp_controller.ex b/lib/philomena_web/controllers/registration/totp_controller.ex index 3cea3279..9316aeb2 100644 --- a/lib/philomena_web/controllers/registration/totp_controller.ex +++ b/lib/philomena_web/controllers/registration/totp_controller.ex @@ -16,7 +16,7 @@ defmodule PhilomenaWeb.Registration.TotpController do |> Repo.update() # Redirect to have the conn pick up the changes - redirect(conn, to: Routes.registration_totp_path(conn, :edit)) + redirect(conn, to: ~p"/registrations/totp/edit") _ -> changeset = Users.change_user(user) @@ -48,7 +48,7 @@ defmodule PhilomenaWeb.Registration.TotpController do {:ok, user} -> conn |> put_flash(:totp_backup_codes, backup_codes) - |> put_session(:user_return_to, Routes.registration_totp_path(conn, :edit)) + |> put_session(:user_return_to, ~p"/registrations/totp/edit") |> UserAuth.totp_auth_user(user, %{}) end end diff --git a/lib/philomena_web/controllers/registration_controller.ex b/lib/philomena_web/controllers/registration_controller.ex index 389ae579..8f3e2bbd 100644 --- a/lib/philomena_web/controllers/registration_controller.ex +++ b/lib/philomena_web/controllers/registration_controller.ex @@ -20,7 +20,7 @@ defmodule PhilomenaWeb.RegistrationController do {:ok, _} = Users.deliver_user_confirmation_instructions( user, - &Routes.confirmation_url(conn, :show, &1) + &url(~p"/confirmations/#{&1}") ) conn diff --git a/lib/philomena_web/controllers/report_controller.ex b/lib/philomena_web/controllers/report_controller.ex index 3169cf02..930ecf13 100644 --- a/lib/philomena_web/controllers/report_controller.ex +++ b/lib/philomena_web/controllers/report_controller.ex @@ -101,7 +101,7 @@ defmodule PhilomenaWeb.ReportController do end defp redirect_path(_conn, nil), do: "/" - defp redirect_path(conn, _user), do: Routes.report_path(conn, :index) + defp redirect_path(conn, _user), do: ~p"/reports" defp max_reports do 5 diff --git a/lib/philomena_web/controllers/session_controller.ex b/lib/philomena_web/controllers/session_controller.ex index ee15bc12..b5704501 100644 --- a/lib/philomena_web/controllers/session_controller.ex +++ b/lib/philomena_web/controllers/session_controller.ex @@ -15,7 +15,7 @@ defmodule PhilomenaWeb.SessionController do Users.get_user_by_email_and_password( email, password, - &Routes.unlock_url(conn, :show, &1) + &url(~p"/unlocks/#{&1}") ) cond do diff --git a/lib/philomena_web/controllers/setting_controller.ex b/lib/philomena_web/controllers/setting_controller.ex index 7c3d6db9..43d4d30a 100644 --- a/lib/philomena_web/controllers/setting_controller.ex +++ b/lib/philomena_web/controllers/setting_controller.ex @@ -25,7 +25,7 @@ defmodule PhilomenaWeb.SettingController do {:ok, conn} -> conn |> put_flash(:info, "Settings updated successfully.") - |> redirect(to: Routes.setting_path(conn, :edit)) + |> redirect(to: ~p"/settings/edit") {:error, changeset} -> conn diff --git a/lib/philomena_web/controllers/tag/alias_controller.ex b/lib/philomena_web/controllers/tag/alias_controller.ex index b7687b1c..b0ed3483 100644 --- a/lib/philomena_web/controllers/tag/alias_controller.ex +++ b/lib/philomena_web/controllers/tag/alias_controller.ex @@ -23,7 +23,7 @@ defmodule PhilomenaWeb.Tag.AliasController do {:ok, tag} -> conn |> put_flash(:info, "Tag alias queued.") - |> redirect(to: Routes.tag_alias_path(conn, :edit, tag)) + |> redirect(to: ~p"/tags/#{tag}/alias/edit") {:error, changeset} -> render(conn, "edit.html", changeset: changeset) @@ -35,6 +35,6 @@ defmodule PhilomenaWeb.Tag.AliasController do conn |> put_flash(:info, "Tag dealias queued.") - |> redirect(to: Routes.tag_path(conn, :show, tag)) + |> redirect(to: ~p"/tags/#{tag}") end end diff --git a/lib/philomena_web/controllers/tag/image_controller.ex b/lib/philomena_web/controllers/tag/image_controller.ex index 2f43ebe8..21d06983 100644 --- a/lib/philomena_web/controllers/tag/image_controller.ex +++ b/lib/philomena_web/controllers/tag/image_controller.ex @@ -24,7 +24,7 @@ defmodule PhilomenaWeb.Tag.ImageController do conn |> put_flash(:info, "Tag image successfully updated.") |> moderation_log(details: &log_details/3, data: tag) - |> redirect(to: Routes.tag_path(conn, :show, tag)) + |> redirect(to: ~p"/tags/#{tag}") {:error, :tag, changeset, _changes} -> render(conn, "edit.html", changeset: changeset) @@ -37,7 +37,7 @@ defmodule PhilomenaWeb.Tag.ImageController do conn |> put_flash(:info, "Tag image successfully removed.") |> moderation_log(details: &log_details/3, data: tag) - |> redirect(to: Routes.tag_path(conn, :show, conn.assigns.tag)) + |> redirect(to: ~p"/tags/#{conn.assigns.tag}") end defp log_details(conn, action, tag) do @@ -49,7 +49,7 @@ defmodule PhilomenaWeb.Tag.ImageController do %{ body: body, - subject_path: Routes.tag_path(conn, :show, tag) + subject_path: ~p"/tags/#{tag}" } end end diff --git a/lib/philomena_web/controllers/tag/reindex_controller.ex b/lib/philomena_web/controllers/tag/reindex_controller.ex index 70b7163c..aee27c28 100644 --- a/lib/philomena_web/controllers/tag/reindex_controller.ex +++ b/lib/philomena_web/controllers/tag/reindex_controller.ex @@ -18,6 +18,6 @@ defmodule PhilomenaWeb.Tag.ReindexController do conn |> put_flash(:info, "Tag reindex started.") - |> redirect(to: Routes.tag_path(conn, :edit, tag)) + |> redirect(to: ~p"/tags/#{tag}/edit") end end diff --git a/lib/philomena_web/controllers/tag_controller.ex b/lib/philomena_web/controllers/tag_controller.ex index 46eb95b7..3fac85cd 100644 --- a/lib/philomena_web/controllers/tag_controller.ex +++ b/lib/philomena_web/controllers/tag_controller.ex @@ -98,7 +98,7 @@ defmodule PhilomenaWeb.TagController do conn |> put_flash(:info, "Tag successfully updated.") |> moderation_log(details: &log_details/3, data: tag) - |> redirect(to: Routes.tag_path(conn, :show, tag)) + |> redirect(to: ~p"/tags/#{tag}") {:error, changeset} -> render(conn, "edit.html", changeset: changeset) @@ -167,7 +167,7 @@ defmodule PhilomenaWeb.TagController do :info, "This tag (\"#{conn.assigns.tag.name}\") has been aliased into the tag \"#{tag.name}\"." ) - |> redirect(to: Routes.tag_path(conn, :show, tag)) + |> redirect(to: ~p"/tags/#{tag}") |> halt() end end @@ -181,7 +181,7 @@ defmodule PhilomenaWeb.TagController do %{ body: body, - subject_path: Routes.tag_path(conn, :show, tag) + subject_path: ~p"/tags/#{tag}" } end end diff --git a/lib/philomena_web/controllers/topic/hide_controller.ex b/lib/philomena_web/controllers/topic/hide_controller.ex index 3149501d..247741d5 100644 --- a/lib/philomena_web/controllers/topic/hide_controller.ex +++ b/lib/philomena_web/controllers/topic/hide_controller.ex @@ -28,12 +28,12 @@ defmodule PhilomenaWeb.Topic.HideController do conn |> put_flash(:info, "Topic successfully hidden!") |> moderation_log(details: &log_details/3, data: topic) - |> redirect(to: Routes.forum_topic_path(conn, :show, topic.forum, topic)) + |> redirect(to: ~p"/forums/#{topic.forum}/topics/#{topic}") {:error, _changeset} -> conn |> put_flash(:error, "Unable to hide the topic!") - |> redirect(to: Routes.forum_topic_path(conn, :show, topic.forum, topic)) + |> redirect(to: ~p"/forums/#{topic.forum}/topics/#{topic}") end end @@ -45,12 +45,12 @@ defmodule PhilomenaWeb.Topic.HideController do conn |> put_flash(:info, "Topic successfully restored!") |> moderation_log(details: &log_details/3, data: topic) - |> redirect(to: Routes.forum_topic_path(conn, :show, topic.forum, topic)) + |> redirect(to: ~p"/forums/#{topic.forum}/topics/#{topic}") {:error, _changeset} -> conn |> put_flash(:error, "Unable to restore the topic!") - |> redirect(to: Routes.forum_topic_path(conn, :show, topic.forum, topic)) + |> redirect(to: ~p"/forums/#{topic.forum}/topics/#{topic}") end end @@ -66,7 +66,7 @@ defmodule PhilomenaWeb.Topic.HideController do %{ body: body, - subject_path: Routes.forum_topic_path(conn, :show, topic.forum, topic) + subject_path: ~p"/forums/#{topic.forum}/topics/#{topic}" } end end diff --git a/lib/philomena_web/controllers/topic/lock_controller.ex b/lib/philomena_web/controllers/topic/lock_controller.ex index 88bf115b..aa4bf13f 100644 --- a/lib/philomena_web/controllers/topic/lock_controller.ex +++ b/lib/philomena_web/controllers/topic/lock_controller.ex @@ -27,12 +27,12 @@ defmodule PhilomenaWeb.Topic.LockController do conn |> put_flash(:info, "Topic successfully locked!") |> moderation_log(details: &log_details/3, data: topic) - |> redirect(to: Routes.forum_topic_path(conn, :show, topic.forum, topic)) + |> redirect(to: ~p"/forums/#{topic.forum}/topics/#{topic}") {:error, _changeset} -> conn |> put_flash(:error, "Unable to lock the topic!") - |> redirect(to: Routes.forum_topic_path(conn, :show, topic.forum, topic)) + |> redirect(to: ~p"/forums/#{topic.forum}/topics/#{topic}") end end @@ -44,12 +44,12 @@ defmodule PhilomenaWeb.Topic.LockController do conn |> put_flash(:info, "Topic successfully unlocked!") |> moderation_log(details: &log_details/3, data: topic) - |> redirect(to: Routes.forum_topic_path(conn, :show, topic.forum, topic)) + |> redirect(to: ~p"/forums/#{topic.forum}/topics/#{topic}") {:error, _changeset} -> conn |> put_flash(:error, "Unable to unlock the topic!") - |> redirect(to: Routes.forum_topic_path(conn, :show, topic.forum, topic)) + |> redirect(to: ~p"/forums/#{topic.forum}/topics/#{topic}") end end @@ -62,7 +62,7 @@ defmodule PhilomenaWeb.Topic.LockController do %{ body: body, - subject_path: Routes.forum_topic_path(conn, :show, topic.forum, topic) + subject_path: ~p"/forums/#{topic.forum}/topics/#{topic}" } end end diff --git a/lib/philomena_web/controllers/topic/move_controller.ex b/lib/philomena_web/controllers/topic/move_controller.ex index f12af72e..d8c91c3f 100644 --- a/lib/philomena_web/controllers/topic/move_controller.ex +++ b/lib/philomena_web/controllers/topic/move_controller.ex @@ -30,19 +30,19 @@ defmodule PhilomenaWeb.Topic.MoveController do conn |> put_flash(:info, "Topic successfully moved!") |> moderation_log(details: &log_details/3, data: topic) - |> redirect(to: Routes.forum_topic_path(conn, :show, topic.forum, topic)) + |> redirect(to: ~p"/forums/#{topic.forum}/topics/#{topic}") {:error, _changeset} -> conn |> put_flash(:error, "Unable to move the topic!") - |> redirect(to: Routes.forum_topic_path(conn, :show, conn.assigns.forum, topic)) + |> redirect(to: ~p"/forums/#{conn.assigns.forum}/topics/#{topic}") end end defp log_details(conn, _action, topic) do %{ body: "Topic '#{topic.title}' moved to #{topic.forum.name}", - subject_path: Routes.forum_topic_path(conn, :show, topic.forum, topic) + subject_path: ~p"/forums/#{topic.forum}/topics/#{topic}" } end end diff --git a/lib/philomena_web/controllers/topic/poll/vote_controller.ex b/lib/philomena_web/controllers/topic/poll/vote_controller.ex index 3af4f011..4ffb4086 100644 --- a/lib/philomena_web/controllers/topic/poll/vote_controller.ex +++ b/lib/philomena_web/controllers/topic/poll/vote_controller.ex @@ -42,12 +42,12 @@ defmodule PhilomenaWeb.Topic.Poll.VoteController do {:ok, _votes} -> conn |> put_flash(:info, "Your vote has been recorded.") - |> redirect(to: Routes.forum_topic_path(conn, :show, topic.forum, topic)) + |> redirect(to: ~p"/forums/#{topic.forum}/topics/#{topic}") _error -> conn |> put_flash(:error, "Your vote was not recorded.") - |> redirect(to: Routes.forum_topic_path(conn, :show, topic.forum, topic)) + |> redirect(to: ~p"/forums/#{topic.forum}/topics/#{topic}") end end @@ -56,7 +56,7 @@ defmodule PhilomenaWeb.Topic.Poll.VoteController do conn |> put_flash(:error, "Your vote was not recorded.") - |> redirect(to: Routes.forum_topic_path(conn, :show, topic.forum, topic)) + |> redirect(to: ~p"/forums/#{topic.forum}/topics/#{topic}") end def delete(conn, %{"id" => poll_vote_id}) do @@ -67,7 +67,7 @@ defmodule PhilomenaWeb.Topic.Poll.VoteController do conn |> put_flash(:info, "Vote successfully removed.") - |> redirect(to: Routes.forum_topic_path(conn, :show, topic.forum, topic)) + |> redirect(to: ~p"/forums/#{topic.forum}/topics/#{topic}") end defp verify_authorized(conn, _opts) do diff --git a/lib/philomena_web/controllers/topic/poll_controller.ex b/lib/philomena_web/controllers/topic/poll_controller.ex index 61cec7d9..b2fdbb81 100644 --- a/lib/philomena_web/controllers/topic/poll_controller.ex +++ b/lib/philomena_web/controllers/topic/poll_controller.ex @@ -27,9 +27,7 @@ defmodule PhilomenaWeb.Topic.PollController do {:ok, _poll} -> conn |> put_flash(:info, "Poll successfully updated.") - |> redirect( - to: Routes.forum_topic_path(conn, :show, conn.assigns.forum, conn.assigns.topic) - ) + |> redirect(to: ~p"/forums/#{conn.assigns.forum}/topics/#{conn.assigns.topic}") {:error, changeset} -> render(conn, "edit.html", changeset: changeset) diff --git a/lib/philomena_web/controllers/topic/post/approve_controller.ex b/lib/philomena_web/controllers/topic/post/approve_controller.ex index 90bf3948..01e11daf 100644 --- a/lib/philomena_web/controllers/topic/post/approve_controller.ex +++ b/lib/philomena_web/controllers/topic/post/approve_controller.ex @@ -23,7 +23,7 @@ defmodule PhilomenaWeb.Topic.Post.ApproveController do |> moderation_log(details: &log_details/3, data: post) |> redirect( to: - Routes.forum_topic_path(conn, :show, post.topic.forum, post.topic, post_id: post.id) <> + ~p"/forums/#{post.topic.forum}/topics/#{post.topic}?#{[post_id: post.id]}" <> "#post_#{post.id}" ) @@ -32,7 +32,7 @@ defmodule PhilomenaWeb.Topic.Post.ApproveController do |> put_flash(:error, "Unable to approve post!") |> redirect( to: - Routes.forum_topic_path(conn, :show, post.topic.forum, post.topic, post_id: post.id) <> + ~p"/forums/#{post.topic.forum}/topics/#{post.topic}?#{[post_id: post.id]}" <> "#post_#{post.id}" ) end @@ -42,7 +42,7 @@ defmodule PhilomenaWeb.Topic.Post.ApproveController do %{ body: "Approved forum post ##{post.id} in topic '#{post.topic.title}'", subject_path: - Routes.forum_topic_path(conn, :show, post.topic.forum, post.topic, post_id: post.id) <> + ~p"/forums/#{post.topic.forum}/topics/#{post.topic}?#{[post_id: post.id]}" <> "#post_#{post.id}" } end diff --git a/lib/philomena_web/controllers/topic/post/delete_controller.ex b/lib/philomena_web/controllers/topic/post/delete_controller.ex index 9e6d7a45..72e39536 100644 --- a/lib/philomena_web/controllers/topic/post/delete_controller.ex +++ b/lib/philomena_web/controllers/topic/post/delete_controller.ex @@ -22,7 +22,7 @@ defmodule PhilomenaWeb.Topic.Post.DeleteController do |> moderation_log(details: &log_details/3, data: post) |> redirect( to: - Routes.forum_topic_path(conn, :show, post.topic.forum, post.topic, post_id: post.id) <> + ~p"/forums/#{post.topic.forum}/topics/#{post.topic}?#{[post_id: post.id]}" <> "#post_#{post.id}" ) @@ -31,7 +31,7 @@ defmodule PhilomenaWeb.Topic.Post.DeleteController do |> put_flash(:error, "Unable to destroy post!") |> redirect( to: - Routes.forum_topic_path(conn, :show, post.topic.forum, post.topic, post_id: post.id) <> + ~p"/forums/#{post.topic.forum}/topics/#{post.topic}?#{[post_id: post.id]}" <> "#post_#{post.id}" ) end @@ -41,7 +41,7 @@ defmodule PhilomenaWeb.Topic.Post.DeleteController do %{ body: "Destroyed forum post ##{post.id} in topic '#{post.topic.title}'", subject_path: - Routes.forum_topic_path(conn, :show, post.topic.forum, post.topic, post_id: post.id) <> + ~p"/forums/#{post.topic.forum}/topics/#{post.topic}?#{[post_id: post.id]}" <> "#post_#{post.id}" } end diff --git a/lib/philomena_web/controllers/topic/post/hide_controller.ex b/lib/philomena_web/controllers/topic/post/hide_controller.ex index 9e449977..ed3f69d9 100644 --- a/lib/philomena_web/controllers/topic/post/hide_controller.ex +++ b/lib/philomena_web/controllers/topic/post/hide_controller.ex @@ -23,7 +23,7 @@ defmodule PhilomenaWeb.Topic.Post.HideController do |> moderation_log(details: &log_details/3, data: post) |> redirect( to: - Routes.forum_topic_path(conn, :show, post.topic.forum, post.topic, post_id: post.id) <> + ~p"/forums/#{post.topic.forum}/topics/#{post.topic}?#{[post_id: post.id]}" <> "#post_#{post.id}" ) @@ -32,7 +32,7 @@ defmodule PhilomenaWeb.Topic.Post.HideController do |> put_flash(:error, "Unable to hide post!") |> redirect( to: - Routes.forum_topic_path(conn, :show, post.topic.forum, post.topic, post_id: post.id) <> + ~p"/forums/#{post.topic.forum}/topics/#{post.topic}?#{[post_id: post.id]}" <> "#post_#{post.id}" ) end @@ -48,7 +48,7 @@ defmodule PhilomenaWeb.Topic.Post.HideController do |> moderation_log(details: &log_details/3, data: post) |> redirect( to: - Routes.forum_topic_path(conn, :show, post.topic.forum, post.topic, post_id: post.id) <> + ~p"/forums/#{post.topic.forum}/topics/#{post.topic}?#{[post_id: post.id]}" <> "#post_#{post.id}" ) @@ -57,7 +57,7 @@ defmodule PhilomenaWeb.Topic.Post.HideController do |> put_flash(:error, "Unable to unhide post!") |> redirect( to: - Routes.forum_topic_path(conn, :show, post.topic.forum, post.topic, post_id: post.id) <> + ~p"/forums/#{post.topic.forum}/topics/#{post.topic}?#{[post_id: post.id]}" <> "#post_#{post.id}" ) end @@ -76,7 +76,7 @@ defmodule PhilomenaWeb.Topic.Post.HideController do %{ body: body, subject_path: - Routes.forum_topic_path(conn, :show, post.topic.forum, post.topic, post_id: post.id) <> + ~p"/forums/#{post.topic.forum}/topics/#{post.topic}?#{[post_id: post.id]}" <> "#post_#{post.id}" } end diff --git a/lib/philomena_web/controllers/topic/post/report_controller.ex b/lib/philomena_web/controllers/topic/post/report_controller.ex index 2d29f7b8..f09df511 100644 --- a/lib/philomena_web/controllers/topic/post/report_controller.ex +++ b/lib/philomena_web/controllers/topic/post/report_controller.ex @@ -26,7 +26,7 @@ defmodule PhilomenaWeb.Topic.Post.ReportController do def new(conn, _params) do topic = conn.assigns.topic post = conn.assigns.post - action = Routes.forum_topic_post_report_path(conn, :create, topic.forum, topic, post) + action = ~p"/forums/#{topic.forum}/topics/#{topic}/posts/#{post}/reports" changeset = %Report{reportable_type: "Post", reportable_id: post.id} @@ -40,7 +40,7 @@ defmodule PhilomenaWeb.Topic.Post.ReportController do def create(conn, params) do topic = conn.assigns.topic post = conn.assigns.post - action = Routes.forum_topic_post_report_path(conn, :create, topic.forum, topic, post) + action = ~p"/forums/#{topic.forum}/topics/#{topic}/posts/#{post}/reports" ReportController.create(conn, action, post, "Post", params) end diff --git a/lib/philomena_web/controllers/topic/post_controller.ex b/lib/philomena_web/controllers/topic/post_controller.ex index 9570c014..8f90abd0 100644 --- a/lib/philomena_web/controllers/topic/post_controller.ex +++ b/lib/philomena_web/controllers/topic/post_controller.ex @@ -58,14 +58,14 @@ defmodule PhilomenaWeb.Topic.PostController do |> put_flash(:info, "Post created successfully.") |> redirect( to: - Routes.forum_topic_path(conn, :show, forum, topic, post_id: post.id) <> + ~p"/forums/#{forum}/topics/#{topic}?#{[post_id: post.id]}" <> "#post_#{post.id}" ) _error -> conn |> put_flash(:error, "There was an error creating the post") - |> redirect(to: Routes.forum_topic_path(conn, :show, forum, topic)) + |> redirect(to: ~p"/forums/#{forum}/topics/#{topic}") end end @@ -88,7 +88,7 @@ defmodule PhilomenaWeb.Topic.PostController do |> put_flash(:info, "Post successfully edited.") |> redirect( to: - Routes.forum_topic_path(conn, :show, post.topic.forum, post.topic, post_id: post.id) <> + ~p"/forums/#{post.topic.forum}/topics/#{post.topic}?#{[post_id: post.id]}" <> "#post_#{post.id}" ) diff --git a/lib/philomena_web/controllers/topic/stick_controller.ex b/lib/philomena_web/controllers/topic/stick_controller.ex index 27f92168..d413be6d 100644 --- a/lib/philomena_web/controllers/topic/stick_controller.ex +++ b/lib/philomena_web/controllers/topic/stick_controller.ex @@ -26,12 +26,12 @@ defmodule PhilomenaWeb.Topic.StickController do conn |> put_flash(:info, "Topic successfully stickied!") |> moderation_log(details: &log_details/3, data: topic) - |> redirect(to: Routes.forum_topic_path(conn, :show, topic.forum, topic)) + |> redirect(to: ~p"/forums/#{topic.forum}/topics/#{topic}") {:error, _changeset} -> conn |> put_flash(:error, "Unable to stick the topic!") - |> redirect(to: Routes.forum_topic_path(conn, :show, topic.forum, topic)) + |> redirect(to: ~p"/forums/#{topic.forum}/topics/#{topic}") end end @@ -43,12 +43,12 @@ defmodule PhilomenaWeb.Topic.StickController do conn |> put_flash(:info, "Topic successfully unstickied!") |> moderation_log(details: &log_details/3, data: topic) - |> redirect(to: Routes.forum_topic_path(conn, :show, topic.forum, topic)) + |> redirect(to: ~p"/forums/#{topic.forum}/topics/#{topic}") {:error, _changeset} -> conn |> put_flash(:error, "Unable to unstick the topic!") - |> redirect(to: Routes.forum_topic_path(conn, :show, topic.forum, topic)) + |> redirect(to: ~p"/forums/#{topic.forum}/topics/#{topic}") end end @@ -61,7 +61,7 @@ defmodule PhilomenaWeb.Topic.StickController do %{ body: body, - subject_path: Routes.forum_topic_path(conn, :show, topic.forum, topic) + subject_path: ~p"/forums/#{topic.forum}/topics/#{topic}" } end end diff --git a/lib/philomena_web/controllers/topic_controller.ex b/lib/philomena_web/controllers/topic_controller.ex index 4c433be2..e88670a0 100644 --- a/lib/philomena_web/controllers/topic_controller.ex +++ b/lib/philomena_web/controllers/topic_controller.ex @@ -128,7 +128,7 @@ defmodule PhilomenaWeb.TopicController do conn |> put_flash(:info, "Successfully posted topic.") - |> redirect(to: Routes.forum_topic_path(conn, :show, forum, topic)) + |> redirect(to: ~p"/forums/#{forum}/topics/#{topic}") {:error, :topic, changeset, _} -> conn @@ -137,7 +137,7 @@ defmodule PhilomenaWeb.TopicController do _error -> conn |> put_flash(:error, "There was an error with your submission. Please try again.") - |> redirect(to: Routes.forum_topic_path(conn, :new, forum)) + |> redirect(to: ~p"/forums/#{forum}/topics/new") end end @@ -146,14 +146,12 @@ defmodule PhilomenaWeb.TopicController do {:ok, topic} -> conn |> put_flash(:info, "Successfully updated topic.") - |> redirect(to: Routes.forum_topic_path(conn, :show, conn.assigns.forum, topic)) + |> redirect(to: ~p"/forums/#{conn.assigns.forum}/topics/#{topic}") {:error, _changeset} -> conn |> put_flash(:error, "There was an error with your submission. Please try again.") - |> redirect( - to: Routes.forum_topic_path(conn, :show, conn.assigns.forum, conn.assigns.topic) - ) + |> redirect(to: ~p"/forums/#{conn.assigns.forum}/topics/#{conn.assigns.topic}") end end diff --git a/lib/philomena_web/controllers/unlock_controller.ex b/lib/philomena_web/controllers/unlock_controller.ex index 9ee7b3c5..62e8dc4f 100644 --- a/lib/philomena_web/controllers/unlock_controller.ex +++ b/lib/philomena_web/controllers/unlock_controller.ex @@ -14,7 +14,7 @@ defmodule PhilomenaWeb.UnlockController do if user = Users.get_user_by_email(email) do Users.deliver_user_unlock_instructions( user, - &Routes.unlock_url(conn, :show, &1) + &url(~p"/unlocks/#{&1}") ) end diff --git a/lib/philomena_web/plugs/map_parameter_plug.ex b/lib/philomena_web/plugs/map_parameter_plug.ex index 93b7cce8..36fc7c04 100644 --- a/lib/philomena_web/plugs/map_parameter_plug.ex +++ b/lib/philomena_web/plugs/map_parameter_plug.ex @@ -3,7 +3,7 @@ defmodule PhilomenaWeb.MapParameterPlug do # symphony of failure: # # 1.) Router helpers do not strip nil query parameters. - # iex> Routes.gallery_path(conn, :index, gallery: nil) + # iex> ~p"/galleries?#{[gallery: nil]}" # "/galleries?gallery=" # # 2.) Pagination always sets the parameter in the route in order diff --git a/lib/philomena_web/plugs/tor_plug.ex b/lib/philomena_web/plugs/tor_plug.ex index 8e6cc4e3..bea6b9d2 100644 --- a/lib/philomena_web/plugs/tor_plug.ex +++ b/lib/philomena_web/plugs/tor_plug.ex @@ -27,7 +27,7 @@ defmodule PhilomenaWeb.TorPlug do def maybe_redirect(conn, nil, true) do conn - |> Controller.redirect(to: Routes.session_path(conn, :new)) + |> Controller.redirect(to: ~p"/sessions/new") |> Conn.halt() end diff --git a/lib/philomena_web/plugs/totp_plug.ex b/lib/philomena_web/plugs/totp_plug.ex index 30f87378..6b809123 100644 --- a/lib/philomena_web/plugs/totp_plug.ex +++ b/lib/philomena_web/plugs/totp_plug.ex @@ -33,7 +33,7 @@ defmodule PhilomenaWeb.TotpPlug do _falsy -> conn - |> Phoenix.Controller.redirect(to: Routes.session_totp_path(conn, :new)) + |> Phoenix.Controller.redirect(to: ~p"/sessions/totp/new") |> Plug.Conn.halt() end end diff --git a/lib/philomena_web/templates/activity/_channel_strip.html.slime b/lib/philomena_web/templates/activity/_channel_strip.html.slime index 34acd120..278cc6e9 100644 --- a/lib/philomena_web/templates/activity/_channel_strip.html.slime +++ b/lib/philomena_web/templates/activity/_channel_strip.html.slime @@ -1,7 +1,7 @@ .block__content.flex.alternating-color .flex__grow / TODO - a href=Routes.channel_path(@conn, :show, @channel) + a href=~p"/channels/#{@channel}" /- if channel.channel_image.present? / => image_tag channel.uploaded_channel_image.url, width: 32, height: 32, alt: "#{channel.title}'s logo'", class: 'channel-strip__image' /- else diff --git a/lib/philomena_web/templates/activity/_topic_strip.html.slime b/lib/philomena_web/templates/activity/_topic_strip.html.slime index 68ae4913..8dc09e01 100644 --- a/lib/philomena_web/templates/activity/_topic_strip.html.slime +++ b/lib/philomena_web/templates/activity/_topic_strip.html.slime @@ -4,7 +4,7 @@ = if @topic.last_post do span.hyphenate-breaks = render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: @topic.last_post, conn: @conn - = link("replied to", to: Routes.forum_topic_path(@conn, :show, @topic.forum, @topic, post_id: @topic.last_post) <> "#post_#{@topic.last_post.id}") - =<> link(@topic.title, to: Routes.forum_topic_path(@conn, :show, @topic.forum, @topic)) + = link("replied to", to: ~p"/forums/#{@topic.forum}/topics/#{@topic}?#{[post_id: @topic.last_post]}" <> "#post_#{@topic.last_post.id}") + =<> link(@topic.title, to: ~p"/forums/#{@topic.forum}/topics/#{@topic}") ' in - => link(@topic.forum.name, to: Routes.forum_path(@conn, :show, @topic.forum)) + => link(@topic.forum.name, to: ~p"/forums/#{@topic.forum}") diff --git a/lib/philomena_web/templates/activity/index.html.slime b/lib/philomena_web/templates/activity/index.html.slime index 167296f9..f6f0a712 100644 --- a/lib/philomena_web/templates/activity/index.html.slime +++ b/lib/philomena_web/templates/activity/index.html.slime @@ -51,4 +51,4 @@ ' Browse Watched Images .block__content.js-resizable-media-container = for image <- @watched do - = render PhilomenaWeb.ImageView, "_image_box.html", image: image, link: Routes.image_path(@conn, :show, image, q: "my:watched"), size: :thumb_small, conn: @conn + = render PhilomenaWeb.ImageView, "_image_box.html", image: image, link: ~p"/images/#{image}?#{[q: "my:watched"]}", size: :thumb_small, conn: @conn diff --git a/lib/philomena_web/templates/admin/advert/_form.html.slime b/lib/philomena_web/templates/admin/advert/_form.html.slime index df77528e..9fcd46c7 100644 --- a/lib/philomena_web/templates/admin/advert/_form.html.slime +++ b/lib/philomena_web/templates/admin/advert/_form.html.slime @@ -14,7 +14,7 @@ = error_tag f, :image_height - else .field - = link "Change image", to: Routes.admin_advert_image_path(@conn, :edit, @changeset.data), class: "button" + = link "Change image", to: ~p"/admin/adverts/#{@changeset.data}/image/edit", class: "button" .field => label f, :link, "Link which the advert should take users to:" diff --git a/lib/philomena_web/templates/admin/advert/edit.html.slime b/lib/philomena_web/templates/admin/advert/edit.html.slime index fba601a0..a3764720 100644 --- a/lib/philomena_web/templates/admin/advert/edit.html.slime +++ b/lib/philomena_web/templates/admin/advert/edit.html.slime @@ -1,2 +1,2 @@ h1 Editing advert -= render PhilomenaWeb.Admin.AdvertView, "_form.html", changeset: @changeset, action: Routes.admin_advert_path(@conn, :update, @advert), conn: @conn += render PhilomenaWeb.Admin.AdvertView, "_form.html", changeset: @changeset, action: ~p"/admin/adverts/#{@advert}", conn: @conn diff --git a/lib/philomena_web/templates/admin/advert/image/edit.html.slime b/lib/philomena_web/templates/admin/advert/image/edit.html.slime index 6055e6a3..6374e9c3 100644 --- a/lib/philomena_web/templates/admin/advert/image/edit.html.slime +++ b/lib/philomena_web/templates/admin/advert/image/edit.html.slime @@ -1,6 +1,6 @@ h2 Edit Advert -= form_for @changeset, Routes.admin_advert_image_path(@conn, :update, @advert), [multipart: true], fn f -> += form_for @changeset, ~p"/admin/adverts/#{@advert}/image", [multipart: true], fn f -> = if @changeset.action do .alert.alert-danger p Oops, something went wrong! Please check the errors below. diff --git a/lib/philomena_web/templates/admin/advert/index.html.slime b/lib/philomena_web/templates/admin/advert/index.html.slime index 1c7e34d3..609d468e 100644 --- a/lib/philomena_web/templates/admin/advert/index.html.slime +++ b/lib/philomena_web/templates/admin/advert/index.html.slime @@ -1,9 +1,9 @@ -- route = fn p -> Routes.admin_advert_path(@conn, :index, p) end +- route = fn p -> ~p"/admin/adverts?#{p}" end - pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @adverts, route: route .block .block__header - a href=Routes.admin_advert_path(@conn, :new) + a href=~p"/admin/adverts/new" i.fa.fa-plus> ' New advert @@ -65,9 +65,9 @@ = advert.clicks td - => link "Edit", to: Routes.admin_advert_path(@conn, :edit, advert) + => link "Edit", to: ~p"/admin/adverts/#{advert}/edit" ' • - = link "Destroy", to: Routes.admin_advert_path(@conn, :delete, advert), data: [confirm: "Are you really, really sure?", method: "delete"] + = link "Destroy", to: ~p"/admin/adverts/#{advert}", data: [confirm: "Are you really, really sure?", method: "delete"] .block__header.block__header--light = pagination diff --git a/lib/philomena_web/templates/admin/advert/new.html.slime b/lib/philomena_web/templates/admin/advert/new.html.slime index ab27e617..76472e47 100644 --- a/lib/philomena_web/templates/admin/advert/new.html.slime +++ b/lib/philomena_web/templates/admin/advert/new.html.slime @@ -1,2 +1,2 @@ h1 New advert -= render PhilomenaWeb.Admin.AdvertView, "_form.html", changeset: @changeset, action: Routes.admin_advert_path(@conn, :create), conn: @conn += render PhilomenaWeb.Admin.AdvertView, "_form.html", changeset: @changeset, action: ~p"/admin/adverts", conn: @conn diff --git a/lib/philomena_web/templates/admin/approval/_approvals.html.slime b/lib/philomena_web/templates/admin/approval/_approvals.html.slime index b254f6dd..f0448000 100644 --- a/lib/philomena_web/templates/admin/approval/_approvals.html.slime +++ b/lib/philomena_web/templates/admin/approval/_approvals.html.slime @@ -12,13 +12,13 @@ .block__content.alternating-color .approval-grid .approval-items--main - span = link ">>#{image.id}", to: Routes.image_path(@conn, :show, image) + span = link ">>#{image.id}", to: ~p"/images/#{image}" .approval-items__details class=class_for_image(image) span = image_thumb(@conn, image) span = warning_text(image) span = if image.user do - = link image.user.name, to: Routes.profile_path(@conn, :show, image.user) + = link image.user.name, to: ~p"/profiles/#{image.user}" - else em> = truncated_ip_link(@conn, image.ip) @@ -26,9 +26,9 @@ span = pretty_time(image.created_at) .approval-items--footer = if can?(@conn, :approve, image) do - = button_to "Approve", Routes.image_approve_path(@conn, :create, image), method: "post", class: "button button--state-success" + = button_to "Approve", ~p"/images/#{image}/approve", method: "post", class: "button button--state-success" = if can?(@conn, :hide, image) do - = form_for :image, Routes.image_delete_path(@conn, :create, image), [method: "post"], fn f -> + = form_for :image, ~p"/images/#{image}/delete", [method: "post"], fn f -> .field.field--inline = text_input f, :deletion_reason, class: "input input--wide", placeholder: "Rule violation", required: true = submit "Delete", class: "button button--state-danger button--separate-left" diff --git a/lib/philomena_web/templates/admin/approval/index.html.slime b/lib/philomena_web/templates/admin/approval/index.html.slime index 818f7ae1..d3f8e098 100644 --- a/lib/philomena_web/templates/admin/approval/index.html.slime +++ b/lib/philomena_web/templates/admin/approval/index.html.slime @@ -1,4 +1,4 @@ -- route = fn p -> Routes.admin_approval_path(@conn, :index, p) end +- route = fn p -> ~p"/admin/approvals?#{p}" end - pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @images, route: route h1 Approval Queue diff --git a/lib/philomena_web/templates/admin/artist_link/index.html.slime b/lib/philomena_web/templates/admin/artist_link/index.html.slime index b9d0e8db..633ff2c1 100644 --- a/lib/philomena_web/templates/admin/artist_link/index.html.slime +++ b/lib/philomena_web/templates/admin/artist_link/index.html.slime @@ -2,20 +2,20 @@ h1 Artist Links p Link creation is done via the Users menu. p Verifying a link will automatically award an artist badge if the link is public, no artist badge exists, and an "artist:" tag is specified. -= form_for :artist_link, Routes.admin_artist_link_path(@conn, :index), [method: "get", class: "hform"], fn f -> += form_for :artist_link, ~p"/admin/artist_links", [method: "get", class: "hform"], fn f -> .field = text_input f, :q, name: :q, value: @conn.params["q"], class: "input hform__text", placeholder: "Search query", autocapitalize: "none" = submit "Search", class: "hform__button button" -- route = fn p -> Routes.admin_artist_link_path(@conn, :index, p) end +- route = fn p -> ~p"/admin/artist_links?#{p}" end - pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @artist_links, route: route, params: link_scope(@conn), conn: @conn .block .block__header = if @conn.params["all"] do - = link "Show unverified only", to: Routes.admin_artist_link_path(@conn, :index) + = link "Show unverified only", to: ~p"/admin/artist_links" - else - = link "Show all", to: Routes.admin_artist_link_path(@conn, :index, all: "true") + = link "Show all", to: ~p"/admin/artist_links?#{[all: "true"]}" = pagination @@ -56,20 +56,20 @@ p Verifying a link will automatically award an artist badge if the link is publi = render PhilomenaWeb.TagView, "_tag.html", tag: link.tag, conn: @conn td - => link "View", to: Routes.profile_artist_link_path(@conn, :show, link.user, link) + => link "View", to: ~p"/profiles/#{link.user}/artist_links/#{link}" ' • - = link "Edit", to: Routes.profile_artist_link_path(@conn, :edit, link.user, link) + = link "Edit", to: ~p"/profiles/#{link.user}/artist_links/#{link}/edit" td - => link "Verify", to: Routes.admin_artist_link_verification_path(@conn, :create, link), method: :post + => link "Verify", to: ~p"/admin/artist_links/#{link}/verification", method: :post ' • - => link "Reject", to: Routes.admin_artist_link_reject_path(@conn, :create, link), method: :post + => link "Reject", to: ~p"/admin/artist_links/#{link}/reject", method: :post br = if not verified?(link) do = if contacted?(link) do ' Artist contacted - else - = link "Artist contacted", to: Routes.admin_artist_link_contact_path(@conn, :create, link), method: :post + = link "Artist contacted", to: ~p"/admin/artist_links/#{link}/contact", method: :post td = public_text(link) diff --git a/lib/philomena_web/templates/admin/badge/_form.html.slime b/lib/philomena_web/templates/admin/badge/_form.html.slime index d8af18ab..1e5dc79b 100644 --- a/lib/philomena_web/templates/admin/badge/_form.html.slime +++ b/lib/philomena_web/templates/admin/badge/_form.html.slime @@ -30,6 +30,6 @@ = error_tag f, :image_mime_type - else .field - = link "Change image", to: Routes.admin_badge_image_path(@conn, :edit, @changeset.data), class: "button" + = link "Change image", to: ~p"/admin/badges/#{@changeset.data}/image/edit", class: "button" = submit "Save Badge", class: "button", data: [disable_with: raw("Saving…")] diff --git a/lib/philomena_web/templates/admin/badge/edit.html.slime b/lib/philomena_web/templates/admin/badge/edit.html.slime index 01df2fba..da713050 100644 --- a/lib/philomena_web/templates/admin/badge/edit.html.slime +++ b/lib/philomena_web/templates/admin/badge/edit.html.slime @@ -1,5 +1,5 @@ h2 Edit Badge -= render "_form.html", Map.put(assigns, :action, Routes.admin_badge_path(@conn, :update, @badge)) += render "_form.html", Map.put(assigns, :action, ~p"/admin/badges/#{@badge}") -= link "Back", to: Routes.admin_badge_path(@conn, :index) += link "Back", to: ~p"/admin/badges" diff --git a/lib/philomena_web/templates/admin/badge/image/edit.html.slime b/lib/philomena_web/templates/admin/badge/image/edit.html.slime index ca0d7b4a..90042dbb 100644 --- a/lib/philomena_web/templates/admin/badge/image/edit.html.slime +++ b/lib/philomena_web/templates/admin/badge/image/edit.html.slime @@ -1,6 +1,6 @@ h2 Edit Badge -= form_for @changeset, Routes.admin_badge_image_path(@conn, :update, @badge), [multipart: true], fn f -> += form_for @changeset, ~p"/admin/badges/#{@badge}/image", [multipart: true], fn f -> = if @changeset.action do .alert.alert-danger p Oops, something went wrong! Please check the errors below. diff --git a/lib/philomena_web/templates/admin/badge/index.html.slime b/lib/philomena_web/templates/admin/badge/index.html.slime index b46f6b71..f3949858 100644 --- a/lib/philomena_web/templates/admin/badge/index.html.slime +++ b/lib/philomena_web/templates/admin/badge/index.html.slime @@ -1,11 +1,11 @@ h2 Badges -- route = fn p -> Routes.admin_badge_path(@conn, :index, p) end +- route = fn p -> ~p"/admin/badges?#{p}" end - pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @badges, route: route, conn: @conn .block .block__header - a href=Routes.admin_badge_path(@conn, :new) + a href=~p"/admin/badges/new" i.fa.fa-plus> ' New Badge @@ -28,9 +28,9 @@ h2 Badges = badge_image(badge, width: 32, height: 32) td - => link "Users", to: Routes.admin_badge_user_path(@conn, :index, badge) + => link "Users", to: ~p"/admin/badges/#{badge}/users" ' • - = link "Edit", to: Routes.admin_badge_path(@conn, :edit, badge) + = link "Edit", to: ~p"/admin/badges/#{badge}/edit" .block__header.block__header--light = pagination diff --git a/lib/philomena_web/templates/admin/badge/new.html.slime b/lib/philomena_web/templates/admin/badge/new.html.slime index 72962247..57fc8273 100644 --- a/lib/philomena_web/templates/admin/badge/new.html.slime +++ b/lib/philomena_web/templates/admin/badge/new.html.slime @@ -1,5 +1,5 @@ h2 New Badge -= render "_form.html", Map.put(assigns, :action, Routes.admin_badge_path(@conn, :create)) += render "_form.html", Map.put(assigns, :action, ~p"/admin/badges") -= link "Back", to: Routes.admin_badge_path(@conn, :index) += link "Back", to: ~p"/admin/badges" diff --git a/lib/philomena_web/templates/admin/badge/user/index.html.slime b/lib/philomena_web/templates/admin/badge/user/index.html.slime index dda58bc2..bbb1c116 100644 --- a/lib/philomena_web/templates/admin/badge/user/index.html.slime +++ b/lib/philomena_web/templates/admin/badge/user/index.html.slime @@ -3,7 +3,7 @@ h1 => @badge.title ' badge -- route = fn p -> Routes.admin_badge_user_path(@conn, :index, @badge, p) end +- route = fn p -> ~p"/admin/badges/#{@badge}/users?#{p}" end - pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @users, route: route, conn: @conn .block @@ -19,7 +19,7 @@ h1 = for user <- @users do tr td - = link user.name, to: Routes.profile_path(@conn, :show, user) + = link user.name, to: ~p"/profiles/#{user}" .block__header.block__header--light = pagination diff --git a/lib/philomena_web/templates/admin/dnp_entry/index.html.slime b/lib/philomena_web/templates/admin/dnp_entry/index.html.slime index bc646d59..bf932f69 100644 --- a/lib/philomena_web/templates/admin/dnp_entry/index.html.slime +++ b/lib/philomena_web/templates/admin/dnp_entry/index.html.slime @@ -1,11 +1,11 @@ h2 Do-Not-Post Requests -= form_for :dnp_entry, Routes.admin_dnp_entry_path(@conn, :index), [method: "get", class: "hform"], fn f -> += form_for :dnp_entry, ~p"/admin/dnp_entries", [method: "get", class: "hform"], fn f -> .field = text_input f, :q, name: :q, value: @conn.params["q"], class: "input hform__text", placeholder: "Search query", autocapitalize: "none" = submit "Search", class: "hform__button button" -- route = fn p -> Routes.admin_dnp_entry_path(@conn, :index, p) end +- route = fn p -> ~p"/admin/dnp_entries?#{p}" end - pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @dnp_entries, route: route, params: [states: state_param(@conn.params["states"])] .block @@ -13,10 +13,10 @@ h2 Do-Not-Post Requests = pagination span.block__header__title Display Only: - => link "All Open", to: Routes.admin_dnp_entry_path(@conn, :index, states: ~W(requested claimed rescinded acknowledged)) - => link "Listed", to: Routes.admin_dnp_entry_path(@conn, :index, states: ~W(listed)) - => link "Rescinded", to: Routes.admin_dnp_entry_path(@conn, :index, states: ~W(rescinded acknowledged)) - => link "Closed", to: Routes.admin_dnp_entry_path(@conn, :index, states: ~W(closed)) + => link "All Open", to: ~p"/admin/dnp_entries?#{[states: ~W(requested claimed rescinded acknowledged)]}" + => link "Listed", to: ~p"/admin/dnp_entries?#{[states: ~W(listed)]}" + => link "Rescinded", to: ~p"/admin/dnp_entries?#{[states: ~W(rescinded acknowledged)]}" + => link "Closed", to: ~p"/admin/dnp_entries?#{[states: ~W(closed)]}" .block__content table.table @@ -38,7 +38,7 @@ h2 Do-Not-Post Requests = render PhilomenaWeb.TagView, "_tag.html", tag: request.tag, conn: @conn td - = link request.requesting_user.name, to: Routes.profile_path(@conn, :show, request.requesting_user) + = link request.requesting_user.name, to: ~p"/profiles/#{request.requesting_user}" td = request.dnp_type @@ -51,7 +51,7 @@ h2 Do-Not-Post Requests = if request.modifying_user do ' by - = link request.modifying_user.name, to: Routes.profile_path(@conn, :show, request.modifying_user) + = link request.modifying_user.name, to: ~p"/profiles/#{request.modifying_user}" td = pretty_time(request.created_at) @@ -60,31 +60,31 @@ h2 Do-Not-Post Requests = pretty_time(request.updated_at) td - => link "Show", to: Routes.dnp_entry_path(@conn, :show, request) + => link "Show", to: ~p"/dnp/#{request}" ' • - => link "Send PM", to: Routes.conversation_path(@conn, :new, recipient: request.requesting_user.name) + => link "Send PM", to: ~p"/conversations/new?#{[recipient: request.requesting_user.name]}" = case request.aasm_state do - s when s in ["requested", "claimed"] -> ' • - => link "Claim", to: Routes.admin_dnp_entry_transition_path(@conn, :create, request, state: "claimed"), data: [method: "post", confirm: "Are you really, really sure?"] + => link "Claim", to: ~p"/admin/dnp_entries/#{request}/transition?#{[state: "claimed"]}", data: [method: "post", confirm: "Are you really, really sure?"] ' • - => link "Approve", to: Routes.admin_dnp_entry_transition_path(@conn, :create, request, state: "listed"), data: [method: "post", confirm: "Are you really, really sure?"] + => link "Approve", to: ~p"/admin/dnp_entries/#{request}/transition?#{[state: "listed"]}", data: [method: "post", confirm: "Are you really, really sure?"] ' • - => link "Close", to: Routes.admin_dnp_entry_transition_path(@conn, :create, request, state: "closed"), data: [method: "post", confirm: "Are you really, really sure?"] + => link "Close", to: ~p"/admin/dnp_entries/#{request}/transition?#{[state: "closed"]}", data: [method: "post", confirm: "Are you really, really sure?"] - "listed" -> ' • - => link "Rescind", to: Routes.admin_dnp_entry_transition_path(@conn, :create, request, state: "rescinded"), data: [method: "post", confirm: "Are you really, really sure?"] + => link "Rescind", to: ~p"/admin/dnp_entries/#{request}/transition?#{[state: "rescinded"]}", data: [method: "post", confirm: "Are you really, really sure?"] ' • - = link "Close", to: Routes.admin_dnp_entry_transition_path(@conn, :create, request, state: "closed"), data: [method: "post", confirm: "Are you really, really sure?"] + = link "Close", to: ~p"/admin/dnp_entries/#{request}/transition?#{[state: "closed"]}", data: [method: "post", confirm: "Are you really, really sure?"] - s when s in ["rescinded", "acknowledged"] -> ' • - => link "Claim", to: Routes.admin_dnp_entry_transition_path(@conn, :create, request, state: "acknowledged"), data: [method: "post", confirm: "Are you really, really sure?"] + => link "Claim", to: ~p"/admin/dnp_entries/#{request}/transition?#{[state: "acknowledged"]}", data: [method: "post", confirm: "Are you really, really sure?"] ' • - = link "Close", to: Routes.admin_dnp_entry_transition_path(@conn, :create, request, state: "closed"), data: [method: "post", confirm: "Are you really, really sure?"] + = link "Close", to: ~p"/admin/dnp_entries/#{request}/transition?#{[state: "closed"]}", data: [method: "post", confirm: "Are you really, really sure?"] - _state -> ' • - => link "Claim", to: Routes.admin_dnp_entry_transition_path(@conn, :create, request, state: "claimed"), data: [method: "post", confirm: "Are you really, really sure?"] + => link "Claim", to: ~p"/admin/dnp_entries/#{request}/transition?#{[state: "claimed"]}", data: [method: "post", confirm: "Are you really, really sure?"] diff --git a/lib/philomena_web/templates/admin/donation/_table.html.slime b/lib/philomena_web/templates/admin/donation/_table.html.slime index 7bcd7ac6..023369b4 100644 --- a/lib/philomena_web/templates/admin/donation/_table.html.slime +++ b/lib/philomena_web/templates/admin/donation/_table.html.slime @@ -12,7 +12,7 @@ table.table tr td = if donation.user do - = link donation.user.name, to: Routes.profile_path(@conn, :show, donation.user) + = link donation.user.name, to: ~p"/profiles/#{donation.user}" td = donation.email diff --git a/lib/philomena_web/templates/admin/donation/index.html.slime b/lib/philomena_web/templates/admin/donation/index.html.slime index f27ed0bb..97ed6cac 100644 --- a/lib/philomena_web/templates/admin/donation/index.html.slime +++ b/lib/philomena_web/templates/admin/donation/index.html.slime @@ -1,4 +1,4 @@ -- route = fn p -> Routes.admin_donation_path(@conn, :index, p) end +- route = fn p -> ~p"/admin/donations?#{p}" end - pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @donations, route: route, conn: @conn h1 Donations diff --git a/lib/philomena_web/templates/admin/donation/user/index.html.slime b/lib/philomena_web/templates/admin/donation/user/index.html.slime index dc45ab3e..daf4f6c1 100644 --- a/lib/philomena_web/templates/admin/donation/user/index.html.slime +++ b/lib/philomena_web/templates/admin/donation/user/index.html.slime @@ -6,7 +6,7 @@ = render PhilomenaWeb.Admin.DonationView, "_table.html", donations: @donations, conn: @conn h1 Add Donation - = form_for @changeset, Routes.admin_donation_path(@conn, :create), fn f -> + = form_for @changeset, ~p"/admin/donations", fn f -> .field => label f, :user_id, "User ID:" = number_input f, :user_id, class: "input input--short", value: @user.id diff --git a/lib/philomena_web/templates/admin/fingerprint_ban/edit.html.slime b/lib/philomena_web/templates/admin/fingerprint_ban/edit.html.slime index 2e78f09b..eb424776 100644 --- a/lib/philomena_web/templates/admin/fingerprint_ban/edit.html.slime +++ b/lib/philomena_web/templates/admin/fingerprint_ban/edit.html.slime @@ -1,6 +1,6 @@ h1 Editing ban -= render PhilomenaWeb.Admin.FingerprintBanView, "_form.html", changeset: @changeset, action: Routes.admin_fingerprint_ban_path(@conn, :update, @fingerprint), conn: @conn += render PhilomenaWeb.Admin.FingerprintBanView, "_form.html", changeset: @changeset, action: ~p"/admin/fingerprint_bans/#{@fingerprint}", conn: @conn br -= link "Back", to: Routes.admin_fingerprint_ban_path(@conn, :index) += link "Back", to: ~p"/admin/fingerprint_bans" diff --git a/lib/philomena_web/templates/admin/fingerprint_ban/index.html.slime b/lib/philomena_web/templates/admin/fingerprint_ban/index.html.slime index b173c39a..209ad509 100644 --- a/lib/philomena_web/templates/admin/fingerprint_ban/index.html.slime +++ b/lib/philomena_web/templates/admin/fingerprint_ban/index.html.slime @@ -1,16 +1,16 @@ h1 Fingerprint Bans -- route = fn p -> Routes.admin_fingerprint_ban_path(@conn, :index, p) end +- route = fn p -> ~p"/admin/fingerprint_bans?#{p}" end - pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @fingerprint_bans, route: route, params: page_params(@conn.params) -= form_for :fingerprint_ban, Routes.admin_fingerprint_ban_path(@conn, :index), [method: "get", class: "hform"], fn f -> += form_for :fingerprint_ban, ~p"/admin/fingerprint_bans", [method: "get", class: "hform"], fn f -> .field = text_input f, :q, name: "q", class: "hform__text input", placeholder: "Search" = submit "Search", class: "button hform__button" .block .block__header - a href=Routes.admin_fingerprint_ban_path(@conn, :new) + a href=~p"/admin/fingerprint_bans/new" i.fa.fa-plus> ' New fingerprint ban @@ -31,7 +31,7 @@ h1 Fingerprint Bans = for ban <- @fingerprint_bans do tr td - = link ban.fingerprint, to: Routes.fingerprint_profile_path(@conn, :show, ban.fingerprint) + = link ban.fingerprint, to: ~p"/fingerprint_profiles/#{ban.fingerprint}" td => pretty_time ban.created_at @@ -53,10 +53,10 @@ h1 Fingerprint Bans = ban.generated_ban_id td - => link "Edit", to: Routes.admin_fingerprint_ban_path(@conn, :edit, ban) + => link "Edit", to: ~p"/admin/fingerprint_bans/#{ban}/edit" = if @current_user.role == "admin" do ' • - => link "Destroy", to: Routes.admin_fingerprint_ban_path(@conn, :delete, ban), data: [confirm: "Are you really, really sure?", method: "delete"] + => link "Destroy", to: ~p"/admin/fingerprint_bans/#{ban}", data: [confirm: "Are you really, really sure?", method: "delete"] .block__header.block__header--light = pagination diff --git a/lib/philomena_web/templates/admin/fingerprint_ban/new.html.slime b/lib/philomena_web/templates/admin/fingerprint_ban/new.html.slime index 75db4f62..02d20b60 100644 --- a/lib/philomena_web/templates/admin/fingerprint_ban/new.html.slime +++ b/lib/philomena_web/templates/admin/fingerprint_ban/new.html.slime @@ -1,5 +1,5 @@ h1 New Fingerprint Ban -= render PhilomenaWeb.Admin.FingerprintBanView, "_form.html", changeset: @changeset, action: Routes.admin_fingerprint_ban_path(@conn, :create), conn: @conn += render PhilomenaWeb.Admin.FingerprintBanView, "_form.html", changeset: @changeset, action: ~p"/admin/fingerprint_bans", conn: @conn br -= link "Back", to: Routes.admin_fingerprint_ban_path(@conn, :index) += link "Back", to: ~p"/admin/fingerprint_bans" diff --git a/lib/philomena_web/templates/admin/forum/edit.html.slime b/lib/philomena_web/templates/admin/forum/edit.html.slime index 4f513a09..8d0e959b 100644 --- a/lib/philomena_web/templates/admin/forum/edit.html.slime +++ b/lib/philomena_web/templates/admin/forum/edit.html.slime @@ -1,5 +1,5 @@ h2 Edit Forum -= render "_form.html", Map.put(assigns, :action, Routes.admin_forum_path(@conn, :update, @forum)) += render "_form.html", Map.put(assigns, :action, ~p"/admin/forums/#{@forum}") -= link "Back", to: Routes.admin_forum_path(@conn, :index) += link "Back", to: ~p"/admin/forums" diff --git a/lib/philomena_web/templates/admin/forum/index.html.slime b/lib/philomena_web/templates/admin/forum/index.html.slime index fec3c55c..c1423ece 100644 --- a/lib/philomena_web/templates/admin/forum/index.html.slime +++ b/lib/philomena_web/templates/admin/forum/index.html.slime @@ -9,9 +9,9 @@ table.table = for forum <- @forums do tr td - = link forum.name, to: Routes.forum_path(@conn, :show, forum) + = link forum.name, to: ~p"/forums/#{forum}" td class="text-right" - = link "Edit", to: Routes.admin_forum_path(@conn, :edit, forum) + = link "Edit", to: ~p"/admin/forums/#{forum}/edit" -= link "New Forum", to: Routes.admin_forum_path(@conn, :new) += link "New Forum", to: ~p"/admin/forums/new" diff --git a/lib/philomena_web/templates/admin/forum/new.html.slime b/lib/philomena_web/templates/admin/forum/new.html.slime index 2d6fd0cd..602d7d14 100644 --- a/lib/philomena_web/templates/admin/forum/new.html.slime +++ b/lib/philomena_web/templates/admin/forum/new.html.slime @@ -1,5 +1,5 @@ h2 New Forum -= render "_form.html", Map.put(assigns, :action, Routes.admin_forum_path(@conn, :create)) += render "_form.html", Map.put(assigns, :action, ~p"/admin/forums") -= link "Back", to: Routes.admin_forum_path(@conn, :index) += link "Back", to: ~p"/admin/forums" diff --git a/lib/philomena_web/templates/admin/mod_note/_table.html.slime b/lib/philomena_web/templates/admin/mod_note/_table.html.slime index a47663a7..6c143079 100644 --- a/lib/philomena_web/templates/admin/mod_note/_table.html.slime +++ b/lib/philomena_web/templates/admin/mod_note/_table.html.slime @@ -19,9 +19,9 @@ table.table = pretty_time note.created_at td - = link note.moderator.name, to: Routes.profile_path(@conn, :show, note.moderator) + = link note.moderator.name, to: ~p"/profiles/#{note.moderator}" td - => link "Edit", to: Routes.admin_mod_note_path(@conn, :edit, note) + => link "Edit", to: ~p"/admin/mod_notes/#{note}/edit" ' • - => link "Delete", to: Routes.admin_mod_note_path(@conn, :delete, note), data: [confirm: "Are you really, really sure?", method: "delete"] + => link "Delete", to: ~p"/admin/mod_notes/#{note}", data: [confirm: "Are you really, really sure?", method: "delete"] diff --git a/lib/philomena_web/templates/admin/mod_note/edit.html.slime b/lib/philomena_web/templates/admin/mod_note/edit.html.slime index e9df5556..aed68f42 100644 --- a/lib/philomena_web/templates/admin/mod_note/edit.html.slime +++ b/lib/philomena_web/templates/admin/mod_note/edit.html.slime @@ -3,4 +3,4 @@ h2 => @mod_note.notable_type => @mod_note.notable_id -= render PhilomenaWeb.Admin.ModNoteView, "_form.html", changeset: @changeset, action: Routes.admin_mod_note_path(@conn, :update, @mod_note), conn: @conn += render PhilomenaWeb.Admin.ModNoteView, "_form.html", changeset: @changeset, action: ~p"/admin/mod_notes/#{@mod_note}", conn: @conn diff --git a/lib/philomena_web/templates/admin/mod_note/index.html.slime b/lib/philomena_web/templates/admin/mod_note/index.html.slime index 5b14f76c..580366fc 100644 --- a/lib/philomena_web/templates/admin/mod_note/index.html.slime +++ b/lib/philomena_web/templates/admin/mod_note/index.html.slime @@ -1,4 +1,4 @@ -- route = fn p -> Routes.admin_mod_note_path(@conn, :index, p) end +- route = fn p -> ~p"/admin/mod_notes?#{p}" end - pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @mod_notes, route: route, conn: @conn h2 Mod Notes diff --git a/lib/philomena_web/templates/admin/mod_note/new.html.slime b/lib/philomena_web/templates/admin/mod_note/new.html.slime index 1cb13aea..09d7291e 100644 --- a/lib/philomena_web/templates/admin/mod_note/new.html.slime +++ b/lib/philomena_web/templates/admin/mod_note/new.html.slime @@ -3,4 +3,4 @@ h2 => @conn.params["notable_type"] => @conn.params["notable_id"] -= render PhilomenaWeb.Admin.ModNoteView, "_form.html", changeset: @changeset, action: Routes.admin_mod_note_path(@conn, :create), conn: @conn += render PhilomenaWeb.Admin.ModNoteView, "_form.html", changeset: @changeset, action: ~p"/admin/mod_notes", conn: @conn diff --git a/lib/philomena_web/templates/admin/report/_reports.html.slime b/lib/philomena_web/templates/admin/report/_reports.html.slime index f43f531a..743f51cb 100644 --- a/lib/philomena_web/templates/admin/report/_reports.html.slime +++ b/lib/philomena_web/templates/admin/report/_reports.html.slime @@ -18,7 +18,7 @@ table.table = truncate(report.reason) td = if report.user do - = link report.user.name, to: Routes.profile_path(@conn, :show, report.user) + = link report.user.name, to: ~p"/profiles/#{report.user}" - else em> = truncated_ip_link(@conn, report.ip) @@ -34,20 +34,20 @@ table.table => pretty_state(report) = user_abbrv @conn, report.admin td - => link "Show", to: Routes.admin_report_path(@conn, :show, report) + => link "Show", to: ~p"/admin/reports/#{report}" = if report.open do = if report.user do ' • - => link "Send PM", to: Routes.conversation_path(@conn, :new, recipient: report.user.name) + => link "Send PM", to: ~p"/conversations/new?#{[recipient: report.user.name]}" = if is_nil(report.admin) and not current?(report.admin, @conn.assigns.current_user) do ' • - => link "Claim", to: Routes.admin_report_claim_path(@conn, :create, report), data: [method: "post"] + => link "Claim", to: ~p"/admin/reports/#{report}/claim", data: [method: "post"] = if current?(report.admin, @conn.assigns.current_user) do ' • - => link "Release", to: Routes.admin_report_claim_path(@conn, :delete, report), data: [method: "delete"] + => link "Release", to: ~p"/admin/reports/#{report}/claim", data: [method: "delete"] ' • - => link "Close", to: Routes.admin_report_close_path(@conn, :create, report), data: [method: "post", confirm: "Are you really, really sure?"] + => link "Close", to: ~p"/admin/reports/#{report}/close", data: [method: "post", confirm: "Are you really, really sure?"] diff --git a/lib/philomena_web/templates/admin/report/index.html.slime b/lib/philomena_web/templates/admin/report/index.html.slime index 23f626f1..83c45312 100644 --- a/lib/philomena_web/templates/admin/report/index.html.slime +++ b/lib/philomena_web/templates/admin/report/index.html.slime @@ -1,4 +1,4 @@ -- route = fn p -> Routes.admin_report_path(@conn, :index, p) end +- route = fn p -> ~p"/admin/reports?#{p}" end - pagination = render PhilomenaWeb.PaginationView, "_pagination.html", route: route, page: @reports, conn: @conn, params: [rq: @conn.params["rq"] || "*"] h1 Reports @@ -30,7 +30,7 @@ h1 Reports .block__header.block__header--light = pagination -= form_for :report, Routes.admin_report_path(@conn, :index), [method: "get", class: "hform"], fn f -> += form_for :report, ~p"/admin/reports", [method: "get", class: "hform"], fn f -> .field = text_input f, :rq, name: :rq, value: @conn.params["rq"], class: "input hform__text", placeholder: "Search reports", autocapitalize: "none" = submit "Search", class: "hform__button button" diff --git a/lib/philomena_web/templates/admin/report/show.html.slime b/lib/philomena_web/templates/admin/report/show.html.slime index f046aae3..d0d183a8 100644 --- a/lib/philomena_web/templates/admin/report/show.html.slime +++ b/lib/philomena_web/templates/admin/report/show.html.slime @@ -31,18 +31,18 @@ article.block.communication = if assigns[:mod_notes] do h4 Mod Notes = render PhilomenaWeb.Admin.ModNoteView, "_table.html", mod_notes: @mod_notes, conn: @conn - = link "Add New Note", to: Routes.admin_mod_note_path(@conn, :new, notable_id: @report.id, notable_type: "Report") + = link "Add New Note", to: ~p"/admin/mod_notes/new?#{[notable_id: @report.id, notable_type: "Report"]}" p = if @report.user do - => link "Send PM", to: Routes.conversation_path(@conn, :new, recipient: @report.user.name), class: "button button--link" + => link "Send PM", to: ~p"/conversations/new?#{[recipient: @report.user.name]}", class: "button button--link" = if @report.open do - => link "Close", to: Routes.admin_report_close_path(@conn, :create, @report), class: "button", data: [method: "post"] + => link "Close", to: ~p"/admin/reports/#{@report}/close", class: "button", data: [method: "post"] = if current?(@report.admin, @conn.assigns.current_user) do - => link "Release", to: Routes.admin_report_claim_path(@conn, :delete, @report), class: "button", data: [method: "delete"] + => link "Release", to: ~p"/admin/reports/#{@report}/claim", class: "button", data: [method: "delete"] - else - => link "Claim", to: Routes.admin_report_claim_path(@conn, :create, @report), class: "button", data: [method: "post"] + => link "Claim", to: ~p"/admin/reports/#{@report}/claim", class: "button", data: [method: "post"] -= link "Back", to: Routes.admin_report_path(@conn, :index), class: "button button-link" += link "Back", to: ~p"/admin/reports", class: "button button-link" diff --git a/lib/philomena_web/templates/admin/site_notice/edit.html.slime b/lib/philomena_web/templates/admin/site_notice/edit.html.slime index bd745654..de39c73e 100644 --- a/lib/philomena_web/templates/admin/site_notice/edit.html.slime +++ b/lib/philomena_web/templates/admin/site_notice/edit.html.slime @@ -1,2 +1,2 @@ h1 Editing site notice -= render PhilomenaWeb.Admin.SiteNoticeView, "_form.html", changeset: @changeset, action: Routes.admin_site_notice_path(@conn, :update, @site_notice), conn: @conn += render PhilomenaWeb.Admin.SiteNoticeView, "_form.html", changeset: @changeset, action: ~p"/admin/site_notices/#{@site_notice}", conn: @conn diff --git a/lib/philomena_web/templates/admin/site_notice/index.html.slime b/lib/philomena_web/templates/admin/site_notice/index.html.slime index 1ff2ee3f..21cac767 100644 --- a/lib/philomena_web/templates/admin/site_notice/index.html.slime +++ b/lib/philomena_web/templates/admin/site_notice/index.html.slime @@ -1,11 +1,11 @@ h1 Site Notices -- route = fn p -> Routes.admin_site_notice_path(@conn, :index, p) end +- route = fn p -> ~p"/admin/site_notices?#{p}" end - pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @admin_site_notices, route: route, conn: @conn .block .block__header - a href=Routes.admin_site_notice_path(@conn, :new) + a href=~p"/admin/site_notices/new" i.fa.fa-plus> ' New site notice @@ -36,9 +36,9 @@ h1 Site Notices = live_text site_notice td - => link "Edit", to: Routes.admin_site_notice_path(@conn, :edit, site_notice) + => link "Edit", to: ~p"/admin/site_notices/#{site_notice}/edit" ' • - => link "Destroy", to: Routes.admin_site_notice_path(@conn, :delete, site_notice), data: [confirm: "Are you really, really sure?", method: "delete"] + => link "Destroy", to: ~p"/admin/site_notices/#{site_notice}", data: [confirm: "Are you really, really sure?", method: "delete"] .block__header.block__header--light = pagination diff --git a/lib/philomena_web/templates/admin/site_notice/new.html.slime b/lib/philomena_web/templates/admin/site_notice/new.html.slime index b8c2f34b..cf85b793 100644 --- a/lib/philomena_web/templates/admin/site_notice/new.html.slime +++ b/lib/philomena_web/templates/admin/site_notice/new.html.slime @@ -1,2 +1,2 @@ h1 New site notice -= render PhilomenaWeb.Admin.SiteNoticeView, "_form.html", changeset: @changeset, action: Routes.admin_site_notice_path(@conn, :create), conn: @conn += render PhilomenaWeb.Admin.SiteNoticeView, "_form.html", changeset: @changeset, action: ~p"/admin/site_notices", conn: @conn diff --git a/lib/philomena_web/templates/admin/subnet_ban/edit.html.slime b/lib/philomena_web/templates/admin/subnet_ban/edit.html.slime index 98f35634..dc451983 100644 --- a/lib/philomena_web/templates/admin/subnet_ban/edit.html.slime +++ b/lib/philomena_web/templates/admin/subnet_ban/edit.html.slime @@ -1,6 +1,6 @@ h1 Editing ban -= render PhilomenaWeb.Admin.SubnetBanView, "_form.html", changeset: @changeset, action: Routes.admin_subnet_ban_path(@conn, :update, @subnet), conn: @conn += render PhilomenaWeb.Admin.SubnetBanView, "_form.html", changeset: @changeset, action: ~p"/admin/subnet_bans/#{@subnet}", conn: @conn br -= link "Back", to: Routes.admin_subnet_ban_path(@conn, :index) += link "Back", to: ~p"/admin/subnet_bans" diff --git a/lib/philomena_web/templates/admin/subnet_ban/index.html.slime b/lib/philomena_web/templates/admin/subnet_ban/index.html.slime index f6b4dc5d..ff139197 100644 --- a/lib/philomena_web/templates/admin/subnet_ban/index.html.slime +++ b/lib/philomena_web/templates/admin/subnet_ban/index.html.slime @@ -1,16 +1,16 @@ h1 Subnet Bans -- route = fn p -> Routes.admin_subnet_ban_path(@conn, :index, p) end +- route = fn p -> ~p"/admin/subnet_bans?#{p}" end - pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @subnet_bans, route: route, params: page_params(@conn.params) -= form_for :subnet_ban, Routes.admin_subnet_ban_path(@conn, :index), [method: "get", class: "hform"], fn f -> += form_for :subnet_ban, ~p"/admin/subnet_bans", [method: "get", class: "hform"], fn f -> .field = text_input f, :q, name: "q", class: "hform__text input", placeholder: "Search" = submit "Search", class: "button hform__button" .block .block__header - a href=Routes.admin_subnet_ban_path(@conn, :new) + a href=~p"/admin/subnet_bans/new" i.fa.fa-plus> ' New subnet ban @@ -31,7 +31,7 @@ h1 Subnet Bans = for ban <- @subnet_bans do tr td - = link ban.specification, to: Routes.ip_profile_path(@conn, :show, to_string(ban.specification)) + = link ban.specification, to: ~p"/ip_profiles/#{to_string(ban.specification)}" td => pretty_time ban.created_at @@ -53,10 +53,10 @@ h1 Subnet Bans = ban.generated_ban_id td - => link "Edit", to: Routes.admin_subnet_ban_path(@conn, :edit, ban) + => link "Edit", to: ~p"/admin/subnet_bans/#{ban}/edit" = if @current_user.role == "admin" do ' • - => link "Destroy", to: Routes.admin_subnet_ban_path(@conn, :delete, ban), data: [confirm: "Are you really, really sure?", method: "delete"] + => link "Destroy", to: ~p"/admin/subnet_bans/#{ban}", data: [confirm: "Are you really, really sure?", method: "delete"] .block__header.block__header--light = pagination diff --git a/lib/philomena_web/templates/admin/subnet_ban/new.html.slime b/lib/philomena_web/templates/admin/subnet_ban/new.html.slime index 50d01a78..7732231b 100644 --- a/lib/philomena_web/templates/admin/subnet_ban/new.html.slime +++ b/lib/philomena_web/templates/admin/subnet_ban/new.html.slime @@ -1,5 +1,5 @@ h1 New Subnet Ban -= render PhilomenaWeb.Admin.SubnetBanView, "_form.html", changeset: @changeset, action: Routes.admin_subnet_ban_path(@conn, :create), conn: @conn += render PhilomenaWeb.Admin.SubnetBanView, "_form.html", changeset: @changeset, action: ~p"/admin/subnet_bans", conn: @conn br -= link "Back", to: Routes.admin_subnet_ban_path(@conn, :index) += link "Back", to: ~p"/admin/subnet_bans" diff --git a/lib/philomena_web/templates/admin/user/_form.html.slime b/lib/philomena_web/templates/admin/user/_form.html.slime index 34275f4a..faf4218a 100644 --- a/lib/philomena_web/templates/admin/user/_form.html.slime +++ b/lib/philomena_web/templates/admin/user/_form.html.slime @@ -34,7 +34,7 @@ .table-list__label .table-list__label__text Avatar .table-list__label__input - = link "Remove avatar", to: Routes.admin_user_avatar_path(@conn, :delete, @user), class: "button", data: [method: "delete", confirm: "Are you really, really sure?"] + = link "Remove avatar", to: ~p"/admin/users/#{@user}/avatar", class: "button", data: [method: "delete", confirm: "Are you really, really sure?"] .block .block__header diff --git a/lib/philomena_web/templates/admin/user/edit.html.slime b/lib/philomena_web/templates/admin/user/edit.html.slime index bb1e6d02..e7a649de 100644 --- a/lib/philomena_web/templates/admin/user/edit.html.slime +++ b/lib/philomena_web/templates/admin/user/edit.html.slime @@ -1,3 +1,3 @@ h1 Editing user -= render PhilomenaWeb.Admin.UserView, "_form.html", Map.put(assigns, :action, Routes.admin_user_path(@conn, :update, @user)) += render PhilomenaWeb.Admin.UserView, "_form.html", Map.put(assigns, :action, ~p"/admin/users/#{@user}") diff --git a/lib/philomena_web/templates/admin/user/force_filter/new.html.slime b/lib/philomena_web/templates/admin/user/force_filter/new.html.slime index 9d214dd1..eda33725 100644 --- a/lib/philomena_web/templates/admin/user/force_filter/new.html.slime +++ b/lib/philomena_web/templates/admin/user/force_filter/new.html.slime @@ -2,7 +2,7 @@ h1 ' Force-assigning a filter for user = @user.name -= form_for @changeset, Routes.admin_user_force_filter_path(@conn, :create, @user), [method: "post"], fn f -> += form_for @changeset, ~p"/admin/users/#{@user}/force_filter", [method: "post"], fn f -> .field => text_input f, :forced_filter_id, placeholder: "Filter ID", class: "input", required: true .field diff --git a/lib/philomena_web/templates/admin/user/index.html.slime b/lib/philomena_web/templates/admin/user/index.html.slime index cf240141..7157e7d9 100644 --- a/lib/philomena_web/templates/admin/user/index.html.slime +++ b/lib/philomena_web/templates/admin/user/index.html.slime @@ -1,15 +1,15 @@ h1 Users -= form_for :user, Routes.admin_user_path(@conn, :index), [method: "get", class: "hform"], fn f -> += form_for :user, ~p"/admin/users", [method: "get", class: "hform"], fn f -> .field => text_input f, :q, name: "q", class: "hform__text input", placeholder: "Search query" = submit "Search", class: "button hform__button" -=> link "Site staff", to: Routes.admin_user_path(@conn, :index, staff: 1) +=> link "Site staff", to: ~p"/admin/users?#{[staff: 1]}" ' • -=> link "2FA users", to: Routes.admin_user_path(@conn, :index, twofactor: 1) +=> link "2FA users", to: ~p"/admin/users?#{[twofactor: 1]}" -- route = fn p -> Routes.admin_user_path(@conn, :index, p) end +- route = fn p -> ~p"/admin/users?#{p}" end - pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @users, route: route, conn: @conn, params: page_params(@conn.params) .block @@ -30,7 +30,7 @@ h1 Users = for user <- @users do tr td - = link user.name, to: Routes.profile_path(@conn, :show, user) + = link user.name, to: ~p"/profiles/#{user}" = cond do - user.otp_required_for_login -> @@ -71,7 +71,7 @@ h1 Users td = if can?(@conn, :edit, user) do - => link to: Routes.admin_user_path(@conn, :edit, user) do + => link to: ~p"/admin/users/#{user}/edit" do i.fa.fa-fw.fa-user-edit ' Edit @@ -82,11 +82,11 @@ h1 Users /' • = if can?(@conn, :index, Philomena.Bans.User) do - => link to: Routes.admin_user_ban_path(@conn, :new, username: user.name) do + => link to: ~p"/admin/user_bans/new?#{[username: user.name]}" do i.fa.fa-fw.fa-ban ' Ban = if can?(@conn, :edit, Philomena.ArtistLinks.ArtistLink) do - => link to: Routes.profile_artist_link_path(@conn, :new, user) do + => link to: ~p"/profiles/#{user}/artist_links/new" do i.fa.fa-fw.fa-link ' Add link diff --git a/lib/philomena_web/templates/admin/user_ban/edit.html.slime b/lib/philomena_web/templates/admin/user_ban/edit.html.slime index ff4f23bb..604f0ed6 100644 --- a/lib/philomena_web/templates/admin/user_ban/edit.html.slime +++ b/lib/philomena_web/templates/admin/user_ban/edit.html.slime @@ -1,6 +1,6 @@ h1 Editing ban -= render PhilomenaWeb.Admin.UserBanView, "_form.html", changeset: @changeset, action: Routes.admin_user_ban_path(@conn, :update, @user), conn: @conn += render PhilomenaWeb.Admin.UserBanView, "_form.html", changeset: @changeset, action: ~p"/admin/user_bans/#{@user}", conn: @conn br -= link "Back", to: Routes.admin_user_ban_path(@conn, :index) += link "Back", to: ~p"/admin/user_bans" diff --git a/lib/philomena_web/templates/admin/user_ban/index.html.slime b/lib/philomena_web/templates/admin/user_ban/index.html.slime index c81d4ab2..3f76034d 100644 --- a/lib/philomena_web/templates/admin/user_ban/index.html.slime +++ b/lib/philomena_web/templates/admin/user_ban/index.html.slime @@ -1,16 +1,16 @@ h1 User Bans -- route = fn p -> Routes.admin_user_ban_path(@conn, :index, p) end +- route = fn p -> ~p"/admin/user_bans?#{p}" end - pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @user_bans, route: route, params: page_params(@conn.params) -= form_for :user_ban, Routes.admin_user_ban_path(@conn, :index), [method: "get", class: "hform"], fn f -> += form_for :user_ban, ~p"/admin/user_bans", [method: "get", class: "hform"], fn f -> .field = text_input f, :q, name: "q", class: "hform__text input", placeholder: "Search" = submit "Search", class: "button hform__button" .block .block__header - a href=Routes.admin_user_ban_path(@conn, :new) + a href=~p"/admin/user_bans/new" i.fa.fa-plus> ' New user ban @@ -31,7 +31,7 @@ h1 User Bans = for ban <- @user_bans do tr td - = link ban.user.name, to: Routes.profile_path(@conn, :show, ban.user) + = link ban.user.name, to: ~p"/profiles/#{ban.user}" td => pretty_time ban.created_at @@ -53,10 +53,10 @@ h1 User Bans = ban.generated_ban_id td - => link "Edit", to: Routes.admin_user_ban_path(@conn, :edit, ban) + => link "Edit", to: ~p"/admin/user_bans/#{ban}/edit" = if @current_user.role == "admin" do ' • - => link "Destroy", to: Routes.admin_user_ban_path(@conn, :delete, ban), data: [confirm: "Are you really, really sure?", method: "delete"] + => link "Destroy", to: ~p"/admin/user_bans/#{ban}", data: [confirm: "Are you really, really sure?", method: "delete"] .block__header.block__header--light = pagination diff --git a/lib/philomena_web/templates/admin/user_ban/new.html.slime b/lib/philomena_web/templates/admin/user_ban/new.html.slime index 468595cb..cdd82ff8 100644 --- a/lib/philomena_web/templates/admin/user_ban/new.html.slime +++ b/lib/philomena_web/templates/admin/user_ban/new.html.slime @@ -1,5 +1,5 @@ h1 New User Ban -= render PhilomenaWeb.Admin.UserBanView, "_form.html", changeset: @changeset, action: Routes.admin_user_ban_path(@conn, :create), conn: @conn += render PhilomenaWeb.Admin.UserBanView, "_form.html", changeset: @changeset, action: ~p"/admin/user_bans", conn: @conn br -= link "Back", to: Routes.admin_user_ban_path(@conn, :index) += link "Back", to: ~p"/admin/user_bans" diff --git a/lib/philomena_web/templates/advert/_box.html.slime b/lib/philomena_web/templates/advert/_box.html.slime index 652401c9..0193d67c 100644 --- a/lib/philomena_web/templates/advert/_box.html.slime +++ b/lib/philomena_web/templates/advert/_box.html.slime @@ -4,7 +4,7 @@ => link "Click here", to: "/pages/advertising" ' for information! - a#imagespns__link href=Routes.advert_path(@conn, :show, @advert) rel="nofollow" title=@advert.title + a#imagespns__link href=~p"/adverts/#{@advert}" rel="nofollow" title=@advert.title img src=advert_image_url(@advert) alt=@advert.title p diff --git a/lib/philomena_web/templates/api/rss/watched/index.html.eex b/lib/philomena_web/templates/api/rss/watched/index.html.eex index de471d21..09451250 100644 --- a/lib/philomena_web/templates/api/rss/watched/index.html.eex +++ b/lib/philomena_web/templates/api/rss/watched/index.html.eex @@ -3,7 +3,7 @@ Derpibooru Watchlist Your watched tags feed from Derpibooru - <%= Routes.api_rss_watched_url(@conn, :index) %> + <%= url(~p"/api/v1/rss/watched") %> <%= last_build_date() %> <%= for image <- @images do %> @@ -12,14 +12,14 @@ - + "> <%= mouseovertext %> ]]> <%= DateTime.to_iso8601(image.created_at) %> - <%= Routes.image_url(@conn, :show, image) %> - <%= Routes.image_url(@conn, :show, image) %> + <%= url(~p"/images/#{image}") %> + <%= url(~p"/images/#{image}") %> <% end %> diff --git a/lib/philomena_web/templates/avatar/edit.html.slime b/lib/philomena_web/templates/avatar/edit.html.slime index 81bd63f5..3ee56baf 100644 --- a/lib/philomena_web/templates/avatar/edit.html.slime +++ b/lib/philomena_web/templates/avatar/edit.html.slime @@ -8,7 +8,7 @@ p Add a new avatar or remove your existing one here. p Avatars must be less than 1000px tall and wide, and smaller than 300 kilobytes in size. PNG, JPEG, and GIF are acceptable. - = form_for @changeset, Routes.avatar_path(@conn, :update), [method: "put", multipart: true], fn f -> + = form_for @changeset, ~p"/avatar", [method: "put", multipart: true], fn f -> = if @changeset.action do .alert.alert-danger p Oops, something went wrong! Please check the errors below. @@ -37,10 +37,10 @@ => submit "Update my avatar", class: "button" br - = button_to "Remove my avatar", Routes.avatar_path(@conn, :delete), method: "delete", class: "button", data: [confirm: "Are you really, really sure?"] + = button_to "Remove my avatar", ~p"/avatar", method: "delete", class: "button", data: [confirm: "Are you really, really sure?"] br = if blank?(@conn.params["profile"]) do - = link "Back", to: Routes.registration_path(@conn, :edit) + = link "Back", to: ~p"/registrations/edit" - else - = link "Back", to: Routes.profile_path(@conn, :show, @current_user) + = link "Back", to: ~p"/profiles/#{@current_user}" diff --git a/lib/philomena_web/templates/channel/_channel_box.html.slime b/lib/philomena_web/templates/channel/_channel_box.html.slime index 8ca76dee..5182f56c 100644 --- a/lib/philomena_web/templates/channel/_channel_box.html.slime +++ b/lib/philomena_web/templates/channel/_channel_box.html.slime @@ -1,7 +1,7 @@ - link_class = "media-box__header media-box__header--channel media-box__header--link" .media-box - a.media-box__header.media-box__header--channel.media-box__header--link href=Routes.channel_path(@conn, :show, @channel) title=@channel.title + a.media-box__header.media-box__header--channel.media-box__header--link href=~p"/channels/#{@channel}" title=@channel.title = @channel.title || @channel.short_name .media-box__header.media-box__header--channel @@ -17,22 +17,22 @@ | NSFW .media-box__content.media-box__content--channel - a href=Routes.channel_path(@conn, :show, @channel) + a href=~p"/channels/#{@channel}" .image-constrained.media-box__content--channel img src=channel_image(@channel) alt="#{@channel.title}" = if @channel.associated_artist_tag do - a href=Routes.tag_path(@conn, :show, @channel.associated_artist_tag) class=link_class + a href=~p"/tags/#{@channel.associated_artist_tag}" class=link_class i.fa.fa-fw.fa-tags> = @channel.associated_artist_tag.name - else .media-box__header.media-box__header--channel No artist tag = if can?(@conn, :edit, @channel) do - a href=Routes.channel_path(@conn, :edit, @channel) class=link_class + a href=~p"/channels/#{@channel}/edit" class=link_class i.fas.fa-fw.fa-edit> ' Edit - a href=Routes.channel_path(@conn, :delete, @channel) class=link_class data-method="delete" data-confirm="Are you really, really sure?" + a href=~p"/channels/#{@channel}" class=link_class data-method="delete" data-confirm="Are you really, really sure?" i.fas.fa-fw.fa-trash> ' Delete diff --git a/lib/philomena_web/templates/channel/edit.html.slime b/lib/philomena_web/templates/channel/edit.html.slime index 47f0e53b..6eb25d31 100644 --- a/lib/philomena_web/templates/channel/edit.html.slime +++ b/lib/philomena_web/templates/channel/edit.html.slime @@ -1,3 +1,3 @@ h1 Editing Channel -= render PhilomenaWeb.ChannelView, "_form.html", changeset: @changeset, action: Routes.channel_path(@conn, :update, @channel), conn: @conn += render PhilomenaWeb.ChannelView, "_form.html", changeset: @changeset, action: ~p"/channels/#{@channel}", conn: @conn diff --git a/lib/philomena_web/templates/channel/index.html.slime b/lib/philomena_web/templates/channel/index.html.slime index 7fd24c1c..50b0bbaa 100644 --- a/lib/philomena_web/templates/channel/index.html.slime +++ b/lib/philomena_web/templates/channel/index.html.slime @@ -1,9 +1,9 @@ h1 Livestreams -- route = fn p -> Routes.channel_path(@conn, :index, p) end +- route = fn p -> ~p"/channels?#{p}" end - pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @channels, route: route, conn: @conn, params: [cq: @conn.params["cq"]] -= form_for :channels, Routes.channel_path(@conn, :index), [method: "get", class: "hform", enforce_utf8: false], fn f -> += form_for :channels, ~p"/channels", [method: "get", class: "hform", enforce_utf8: false], fn f -> .field = text_input f, :cq, name: :cq, value: @conn.params["cq"], class: "input hform__text", placeholder: "Search channels", autocapitalize: "none" = submit "Search", class: "hform__button button" @@ -13,11 +13,11 @@ h1 Livestreams .page__pagination = pagination = if @conn.cookies["chan_nsfw"] == "true" do - a href=Routes.channel_nsfw_path(@conn, :delete) data-method="delete" + a href=~p"/channels/nsfw" data-method="delete" i.fa.fa-eye-slash> ' Hide NSFW streams - else - a href=Routes.channel_nsfw_path(@conn, :create) data-method="create" + a href=~p"/channels/nsfw" data-method="create" i.fa.fa-eye> ' Show NSFW streams @@ -30,7 +30,7 @@ h1 Livestreams br = if can?(@conn, :create, Philomena.Channels.Channel) do - = link "New Channel", to: Routes.channel_path(@conn, :new) + = link "New Channel", to: ~p"/channels/new" h2 FAQ p diff --git a/lib/philomena_web/templates/channel/new.html.slime b/lib/philomena_web/templates/channel/new.html.slime index 8a3551e9..a7361ef7 100644 --- a/lib/philomena_web/templates/channel/new.html.slime +++ b/lib/philomena_web/templates/channel/new.html.slime @@ -1,3 +1,3 @@ h1 Adding Channel -= render PhilomenaWeb.ChannelView, "_form.html", changeset: @changeset, action: Routes.channel_path(@conn, :create), conn: @conn += render PhilomenaWeb.ChannelView, "_form.html", changeset: @changeset, action: ~p"/channels", conn: @conn diff --git a/lib/philomena_web/templates/channel/subscription/_subscription.html.slime b/lib/philomena_web/templates/channel/subscription/_subscription.html.slime index 362d9115..b0fdd6e3 100644 --- a/lib/philomena_web/templates/channel/subscription/_subscription.html.slime +++ b/lib/philomena_web/templates/channel/subscription/_subscription.html.slime @@ -1,8 +1,8 @@ elixir: - watch_path = Routes.channel_subscription_path(@conn, :create, @channel) + watch_path = ~p"/channels/#{@channel}/subscription" watch_class = if @watching, do: "hidden", else: "" - unwatch_path = Routes.channel_subscription_path(@conn, :delete, @channel) + unwatch_path = ~p"/channels/#{@channel}/subscription" unwatch_class = if @watching, do: "", else: "hidden" = if @conn.assigns.current_user do @@ -17,7 +17,7 @@ elixir: span.hide-mobile ' Unsubscribe - else - a.media-box__header.media-box__header--channel.media-box__header--link href=Routes.session_path(@conn, :new) + a.media-box__header.media-box__header--channel.media-box__header--link href=~p"/sessions/new" i.fa.fa-bell> span.hide-mobile ' Subscribe diff --git a/lib/philomena_web/templates/comment/_comment.html.slime b/lib/philomena_web/templates/comment/_comment.html.slime index 508202ef..1ec574dd 100644 --- a/lib/philomena_web/templates/comment/_comment.html.slime +++ b/lib/philomena_web/templates/comment/_comment.html.slime @@ -9,7 +9,7 @@ article.block.communication id="comment_#{@comment.id}" p ul.horizontal-list li - = link(to: Routes.image_comment_approve_path(@conn, :create, @comment.image_id, @comment), data: [confirm: "Are you sure?"], method: "post", class: "button") do + = link(to: ~p"/images/#{@comment.image_id}/comments/#{@comment}/approve", data: [confirm: "Are you sure?"], method: "post", class: "button") do i.fas.fa-check> ' Approve li @@ -17,7 +17,7 @@ article.block.communication id="comment_#{@comment.id}" i.fa.fa-times> ' Reject - = form_for :comment, Routes.image_comment_hide_path(@conn, :create, @comment.image_id, @comment), [class: "togglable-delete-form hidden flex", id: "inline-reject-form-comment-#{@comment.id}"], fn f -> + = form_for :comment, ~p"/images/#{@comment.image_id}/comments/#{@comment}/hide", [class: "togglable-delete-form hidden flex", id: "inline-reject-form-comment-#{@comment.id}"], fn f -> = text_input f, :deletion_reason, class: "input input--wide", placeholder: "Deletion Reason", id: "inline-reject-reason-comment-#{@comment.id}", required: true = submit "Delete", class: "button" @@ -58,12 +58,12 @@ article.block.communication id="comment_#{@comment.id}" .js-staff-action = cond do - @comment.hidden_from_users and not @comment.destroyed_content -> - = link(to: Routes.image_comment_hide_path(@conn, :delete, @comment.image_id, @comment), data: [confirm: "Are you sure?"], method: "delete", class: "communication__interaction") do + = link(to: ~p"/images/#{@comment.image_id}/comments/#{@comment}/hide", data: [confirm: "Are you sure?"], method: "delete", class: "communication__interaction") do i.fas.fa-check> ' Restore = if can?(@conn, :delete, @comment) do - = link(to: Routes.image_comment_delete_path(@conn, :create, @comment.image_id, @comment), data: [confirm: "Are you sure?"], method: "post", class: "communication__interaction") do + = link(to: ~p"/images/#{@comment.image_id}/comments/#{@comment}/delete", data: [confirm: "Are you sure?"], method: "post", class: "communication__interaction") do i.fas.fa-times> ' Delete Contents @@ -80,6 +80,6 @@ article.block.communication id="comment_#{@comment.id}" .communication__info.js-staff-action =<> link_to_fingerprint(@conn, @comment.fingerprint) - = form_for :comment, Routes.image_comment_hide_path(@conn, :create, @comment.image_id, @comment), [class: "togglable-delete-form hidden flex", id: "inline-del-form-comment-#{@comment.id}"], fn f -> + = form_for :comment, ~p"/images/#{@comment.image_id}/comments/#{@comment}/hide", [class: "togglable-delete-form hidden flex", id: "inline-del-form-comment-#{@comment.id}"], fn f -> = text_input f, :deletion_reason, class: "input input--wide", placeholder: "Deletion Reason", id: "inline-del-reason-comment-#{@comment.id}", required: true = submit "Delete", class: "button" diff --git a/lib/philomena_web/templates/comment/_comment_options.html.slime b/lib/philomena_web/templates/comment/_comment_options.html.slime index 5f8c3674..36167c77 100644 --- a/lib/philomena_web/templates/comment/_comment_options.html.slime +++ b/lib/philomena_web/templates/comment/_comment_options.html.slime @@ -2,13 +2,13 @@ div ' Posted => pretty_time(@comment.created_at) - a.communication__interaction href=Routes.image_comment_report_path(@conn, :new, @comment.image, @comment) + a.communication__interaction href=~p"/images/#{@comment.image}/comments/#{@comment}/reports/new" i.fa.fa-flag> ' Report = if not is_nil(@comment.edited_at) and can?(@conn, :show, @comment) do br - a href=Routes.image_comment_history_path(@conn, :index, @comment.image, @comment) + a href=~p"/images/#{@comment.image}/comments/#{@comment}/history" ' Edited => pretty_time(@comment.edited_at) @@ -17,7 +17,7 @@ div => @comment.edit_reason div - - link_path = Routes.image_path(@conn, :show, @comment.image) <> "#comment_#{@comment.id}" + - link_path = ~p"/images/#{@comment.image}" <> "#comment_#{@comment.id}" - safe_author = PhilomenaWeb.PostView.markdown_safe_author(@comment) - quote_body = if @comment.hidden_from_users, do: "", else: @comment.body @@ -36,6 +36,6 @@ div = if can?(@conn, :edit, @comment) do span.owner-options strong - a.communication__interaction href=Routes.image_comment_path(@conn, :edit, @comment.image, @comment) + a.communication__interaction href=~p"/images/#{@comment.image}/comments/#{@comment}/edit" i.fas.fa-edit> ' Edit diff --git a/lib/philomena_web/templates/comment/_comment_with_image.html.slime b/lib/philomena_web/templates/comment/_comment_with_image.html.slime index 8faaca31..fce128bf 100644 --- a/lib/philomena_web/templates/comment/_comment_with_image.html.slime +++ b/lib/philomena_web/templates/comment/_comment_with_image.html.slime @@ -41,12 +41,12 @@ article.block.communication id="comment_#{@comment.id}" .js-staff-action = cond do - @comment.hidden_from_users and not @comment.destroyed_content -> - = link(to: Routes.image_comment_hide_path(@conn, :delete, @comment.image_id, @comment), data: [confirm: "Are you sure?"], method: "delete", class: "communication__interaction") do + = link(to: ~p"/images/#{@comment.image_id}/comments/#{@comment}/hide", data: [confirm: "Are you sure?"], method: "delete", class: "communication__interaction") do i.fas.fa-check> ' Restore = if can?(@conn, :delete, @comment) do - = link(to: Routes.image_comment_delete_path(@conn, :create, @comment.image_id, @comment), data: [confirm: "Are you sure?"], method: "post", class: "communication__interaction") do + = link(to: ~p"/images/#{@comment.image_id}/comments/#{@comment}/delete", data: [confirm: "Are you sure?"], method: "post", class: "communication__interaction") do i.fas.fa-times> ' Delete Contents @@ -63,6 +63,6 @@ article.block.communication id="comment_#{@comment.id}" .communication__info.js-staff-action =<> link_to_fingerprint(@conn, @comment.fingerprint) - = form_for :comment, Routes.image_comment_hide_path(@conn, :create, @comment.image_id, @comment), [class: "togglable-delete-form hidden flex", id: "inline-del-form-comment-#{@comment.id}"], fn f -> + = form_for :comment, ~p"/images/#{@comment.image_id}/comments/#{@comment}/hide", [class: "togglable-delete-form hidden flex", id: "inline-del-form-comment-#{@comment.id}"], fn f -> = text_input f, :deletion_reason, class: "input input--wide", placeholder: "Deletion Reason", id: "inline-del-reason-comment-#{@comment.id}", required: true = submit "Delete", class: "button" diff --git a/lib/philomena_web/templates/comment/index.html.slime b/lib/philomena_web/templates/comment/index.html.slime index d8bb174f..ae3e2eb0 100644 --- a/lib/philomena_web/templates/comment/index.html.slime +++ b/lib/philomena_web/templates/comment/index.html.slime @@ -1,6 +1,6 @@ h1 Comments -= form_for :comments, Routes.comment_path(@conn, :index), [method: "get", class: "hform", enforce_utf8: false], fn f -> += form_for :comments, ~p"/comments", [method: "get", class: "hform", enforce_utf8: false], fn f -> .field = text_input f, :cq, name: :cq, value: @conn.params["cq"], class: "input hform__text", placeholder: "Search comments", autocapitalize: "none" = submit "Search", class: "hform__button button" @@ -14,7 +14,7 @@ h2 Search Results = cond do - Enum.any?(@comments) -> - - route = fn p -> Routes.comment_path(@conn, :index, p) end + - route = fn p -> ~p"/comments?#{p}" end - pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @comments, route: route, params: [cq: @conn.params["cq"]], conn: @conn = for {body, comment} <- @comments, comment.image.hidden_from_users == false do @@ -68,35 +68,35 @@ table.table td Literal td Matches the author of this comment. Anonymous authors will never match this term. td - code = link "author:Joey", to: Routes.comment_path(@conn, :index, cq: "author:Joey") + code = link "author:Joey", to: ~p"/comments?#{[cq: "author:Joey"]}" tr td code body td Full Text td Matches the body of this comment. This is the default field. td - code = link "body:test", to: Routes.comment_path(@conn, :index, cq: "body:test") + code = link "body:test", to: ~p"/comments?#{[cq: "body:test"]}" tr td code created_at td Date/Time Range td Matches the creation time of this comment. td - code = link "created_at:2015", to: Routes.comment_path(@conn, :index, cq: "created_at:2015") + code = link "created_at:2015", to: ~p"/comments?#{[cq: "created_at:2015"]}" tr td code id td Numeric Range td Matches the numeric surrogate key for this comment. td - code = link "id:1000000", to: Routes.comment_path(@conn, :index, cq: "id:1000000") + code = link "id:1000000", to: ~p"/comments?#{[cq: "id:1000000"]}" tr td code image_id td Literal td Matches the numeric surrogate key for the image this comment belongs to. td - code = link "image_id:1000000", to: Routes.comment_path(@conn, :index, cq: "image_id:1000000") + code = link "image_id:1000000", to: ~p"/comments?#{[cq: "image_id:1000000"]}" tr td code my @@ -105,11 +105,11 @@ table.table code> my:comments ' matches comments you have posted if you are signed in. td - code = link "my:comments", to: Routes.comment_path(@conn, :index, cq: "my:comments") + code = link "my:comments", to: ~p"/comments?#{[cq: "my:comments"]}" tr td code user_id td Literal td Matches comments with the specified user_id. Anonymous users will never match this term. td - code = link "user_id:211190", to: Routes.comment_path(@conn, :index, cq: "user_id:211190") + code = link "user_id:211190", to: ~p"/comments?#{[cq: "user_id:211190"]}" diff --git a/lib/philomena_web/templates/commission/_directory_results.html.slime b/lib/philomena_web/templates/commission/_directory_results.html.slime index b61eed56..a5e7ed0d 100644 --- a/lib/philomena_web/templates/commission/_directory_results.html.slime +++ b/lib/philomena_web/templates/commission/_directory_results.html.slime @@ -1,5 +1,5 @@ elixir: - route = fn p -> Routes.commission_path(@conn, :index, p) end + route = fn p -> ~p"/commissions?#{p}" end pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @commissions, route: route, conn: @conn, params: [commission: @conn.params["commission"]] .block @@ -9,10 +9,10 @@ elixir: .page__options = cond do - not is_nil(@conn.assigns.current_user) and not is_nil(@conn.assigns.current_user.commission) -> - = link "View my listing", to: Routes.profile_commission_path(@conn, :show, @conn.assigns.current_user) + = link "View my listing", to: ~p"/profiles/#{@conn.assigns.current_user}/commission" - not is_nil(@conn.assigns.current_user) -> - = link "Create my listing", to: Routes.profile_commission_path(@conn, :new, @conn.assigns.current_user) + = link "Create my listing", to: ~p"/profiles/#{@conn.assigns.current_user}/commission/new" - true -> @@ -58,7 +58,7 @@ elixir: p strong - = link "More information", to: Routes.profile_commission_path(@conn, :show, c.user) + = link "More information", to: ~p"/profiles/#{c.user}/commission" - true -> p We couldn't find any commission listings to display. Sorry! diff --git a/lib/philomena_web/templates/commission/_directory_sidebar.html.slime b/lib/philomena_web/templates/commission/_directory_sidebar.html.slime index fcfcfe29..6bf4c0a2 100644 --- a/lib/philomena_web/templates/commission/_directory_sidebar.html.slime +++ b/lib/philomena_web/templates/commission/_directory_sidebar.html.slime @@ -2,7 +2,7 @@ .block__header span.block__header__title Search .block__content - = form_for @conn, Routes.commission_path(@conn, :index), [as: :commission, method: "get", class: "hform"], fn f -> + = form_for @conn, ~p"/commissions", [as: :commission, method: "get", class: "hform"], fn f -> .field = label f, :categories, "Art Categories:" = for {name, value} <- categories() do diff --git a/lib/philomena_web/templates/confirmation/new.html.slime b/lib/philomena_web/templates/confirmation/new.html.slime index 2f4a5177..7972f595 100644 --- a/lib/philomena_web/templates/confirmation/new.html.slime +++ b/lib/philomena_web/templates/confirmation/new.html.slime @@ -1,6 +1,6 @@ h1 Resend confirmation instructions -= form_for :user, Routes.confirmation_path(@conn, :create), fn f -> += form_for :user, ~p"/confirmations", fn f -> .field = email_input f, :email, placeholder: "Email", class: "input", required: true diff --git a/lib/philomena_web/templates/conversation/index.html.slime b/lib/philomena_web/templates/conversation/index.html.slime index d8a5aed7..ea476547 100644 --- a/lib/philomena_web/templates/conversation/index.html.slime +++ b/lib/philomena_web/templates/conversation/index.html.slime @@ -1,5 +1,5 @@ elixir: - route = fn p -> Routes.conversation_path(@conn, :index, p) end + route = fn p -> ~p"/conversations?#{p}" end pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @conversations, route: route, conn: @conn h1 My Conversations @@ -8,7 +8,7 @@ h1 My Conversations .page__pagination = pagination .page__info - a href=Routes.conversation_path(@conn, :new) + a href=~p"/conversations/new" i.fa.fa-paper-plane> ' Create New Conversation @@ -23,7 +23,7 @@ h1 My Conversations = for {c, count} <- @conversations do tr class=conversation_class(@conn.assigns.current_user, c) td.table--communication-list__name - => link c.title, to: Routes.conversation_path(@conn, :show, c) + => link c.title, to: ~p"/conversations/#{c}" .small-text.hide-mobile => count @@ -38,7 +38,7 @@ h1 My Conversations td.table--communication-list__options => link "Last message", to: last_message_path(@conn, c, count) ' • - => link "Hide", to: Routes.conversation_hide_path(@conn, :create, c), data: [method: "post"], data: [confirm: "Are you really, really sure?"] + => link "Hide", to: ~p"/conversations/#{c}/hide", data: [method: "post"], data: [confirm: "Are you really, really sure?"] .block__header.block__header--light.page__header .page__pagination = pagination diff --git a/lib/philomena_web/templates/conversation/message/_form.html.slime b/lib/philomena_web/templates/conversation/message/_form.html.slime index 7234a3e7..cbaec375 100644 --- a/lib/philomena_web/templates/conversation/message/_form.html.slime +++ b/lib/philomena_web/templates/conversation/message/_form.html.slime @@ -1,4 +1,4 @@ -= form_for @changeset, Routes.conversation_message_path(@conn, :create, @conversation), fn f -> += form_for @changeset, ~p"/conversations/#{@conversation}/messages", fn f -> .block .communication-edit__wrap = render PhilomenaWeb.MarkdownView, "_input.html", conn: @conn, f: f, action_icon: "pencil-alt", action_text: "Reply" diff --git a/lib/philomena_web/templates/conversation/new.html.slime b/lib/philomena_web/templates/conversation/new.html.slime index a6800652..595daccc 100644 --- a/lib/philomena_web/templates/conversation/new.html.slime +++ b/lib/philomena_web/templates/conversation/new.html.slime @@ -1,7 +1,7 @@ h1 New Conversation .block .block__header - => link "Conversations", to: Routes.conversation_path(@conn, :index) + => link "Conversations", to: ~p"/conversations" ' » span.block__header__title New Conversation @@ -20,7 +20,7 @@ h1 New Conversation - _ -> / Nothing -= form_for @changeset, Routes.conversation_path(@conn, :create), fn f -> += form_for @changeset, ~p"/conversations", fn f -> = if @changeset.action do .alert.alert-danger p Oops, something went wrong! Please check the errors below. diff --git a/lib/philomena_web/templates/conversation/show.html.slime b/lib/philomena_web/templates/conversation/show.html.slime index 9c69b9bc..5af5ead9 100644 --- a/lib/philomena_web/templates/conversation/show.html.slime +++ b/lib/philomena_web/templates/conversation/show.html.slime @@ -1,14 +1,14 @@ elixir: - route = fn p -> Routes.conversation_path(@conn, :show, @conversation, p) end + route = fn p -> ~p"/conversations/#{@conversation}?#{p}" end pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @messages, route: route, conn: @conn other = other_party(@current_user, @conversation) h1 = @conversation.title .block .block__header - => link "Message Center", to: Routes.conversation_path(@conn, :index) + => link "Message Center", to: ~p"/conversations" ' » - => link @conversation.title, to: Routes.conversation_path(@conn, :show, @conversation) + => link @conversation.title, to: ~p"/conversations/#{@conversation}" ' Conversation with => render PhilomenaWeb.UserAttributionView, "_user.html", object: %{user: other}, conn: @conn .block__header--sub.block__header--light.page__header @@ -18,11 +18,11 @@ h1 = @conversation.title .page__pagination = pagination .page__info = if hidden_by?(@current_user, @conversation) do - = link "Restore conversation", to: Routes.conversation_hide_path(@conn, :delete, @conversation), data: [method: "delete"] + = link "Restore conversation", to: ~p"/conversations/#{@conversation}/hide", data: [method: "delete"] - else - = link "Remove conversation", to: Routes.conversation_hide_path(@conn, :create, @conversation), data: [method: "post", confirm: "Are you really, really sure?"] - = link "Report conversation", to: Routes.conversation_report_path(@conn, :new, @conversation) - = link "Mark as unread", to: Routes.conversation_read_path(@conn, :delete, @conversation), data: [method: "delete"] + = link "Remove conversation", to: ~p"/conversations/#{@conversation}/hide", data: [method: "post", confirm: "Are you really, really sure?"] + = link "Report conversation", to: ~p"/conversations/#{@conversation}/reports/new" + = link "Mark as unread", to: ~p"/conversations/#{@conversation}/read", data: [method: "delete"] = for {message, body} <- @messages do = render PhilomenaWeb.MessageView, "_message.html", message: message, body: body, conn: @conn @@ -59,5 +59,5 @@ h1 = @conversation.title p You've managed to send over 1,000 messages in this conversation! p We'd like to ask you to make a new conversation. Don't worry, this one won't go anywhere if you need to refer back to it. p - => link "Click here", to: Routes.conversation_path(@conn, :new, receipient: other.name) + => link "Click here", to: ~p"/conversations/new?#{[receipient: other.name]}" ' to make a new conversation with this user. diff --git a/lib/philomena_web/templates/dnp_entry/edit.html.slime b/lib/philomena_web/templates/dnp_entry/edit.html.slime index 2761b395..969f4ffd 100644 --- a/lib/philomena_web/templates/dnp_entry/edit.html.slime +++ b/lib/philomena_web/templates/dnp_entry/edit.html.slime @@ -1,2 +1,2 @@ h2 Edit DNP Request -= render PhilomenaWeb.DnpEntryView, "_form.html", changeset: @changeset, action: Routes.dnp_entry_path(@conn, :update, @dnp_entry, tag_id: @dnp_entry.tag_id), conn: @conn, selectable_tags: @selectable_tags += render PhilomenaWeb.DnpEntryView, "_form.html", changeset: @changeset, action: ~p"/dnp/#{@dnp_entry}?#{[tag_id: @dnp_entry.tag_id]}", conn: @conn, selectable_tags: @selectable_tags diff --git a/lib/philomena_web/templates/dnp_entry/index.html.slime b/lib/philomena_web/templates/dnp_entry/index.html.slime index 01952ede..b4463eb5 100644 --- a/lib/philomena_web/templates/dnp_entry/index.html.slime +++ b/lib/philomena_web/templates/dnp_entry/index.html.slime @@ -16,13 +16,13 @@ br .block__content = cond do - not is_nil(@current_user) and Enum.any?(@linked_tags) -> - = link "Create an entry", to: Routes.dnp_entry_path(@conn, :new) + = link "Create an entry", to: ~p"/dnp/new" br - = link "My Listings", to: Routes.dnp_entry_path(@conn, :index, mine: "1") + = link "My Listings", to: ~p"/dnp?#{[mine: "1"]}" - not is_nil(@current_user) -> ' You must have a verified artist link to create and manage DNP entries. - = link "Request an artist link", to: Routes.profile_artist_link_path(@conn, :new, @current_user) + = link "Request an artist link", to: ~p"/profiles/#{@current_user}/artist_links/new" | . - true -> @@ -31,7 +31,7 @@ br h3 The List .block - - route = fn p -> Routes.dnp_entry_path(@conn, :index, p) end + - route = fn p -> ~p"/dnp?#{p}" end - pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @dnp_entries, route: route, conn: @conn .block__header.page__header @@ -69,7 +69,7 @@ h3 The List = pretty_time(entry.created_at) td - = link "More Info", to: Routes.dnp_entry_path(@conn, :show, entry) + = link "More Info", to: ~p"/dnp/#{entry}" .block__header.page__header .page__pagination = pagination diff --git a/lib/philomena_web/templates/dnp_entry/new.html.slime b/lib/philomena_web/templates/dnp_entry/new.html.slime index 95c822d2..1bb616f8 100644 --- a/lib/philomena_web/templates/dnp_entry/new.html.slime +++ b/lib/philomena_web/templates/dnp_entry/new.html.slime @@ -1,2 +1,2 @@ h2 New DNP Request -= render PhilomenaWeb.DnpEntryView, "_form.html", changeset: @changeset, action: Routes.dnp_entry_path(@conn, :create, tag_id: @conn.params["tag_id"]), conn: @conn, selectable_tags: @selectable_tags += render PhilomenaWeb.DnpEntryView, "_form.html", changeset: @changeset, action: ~p"/dnp?#{[tag_id: @conn.params["tag_id"]]}", conn: @conn, selectable_tags: @selectable_tags diff --git a/lib/philomena_web/templates/dnp_entry/show.html.slime b/lib/philomena_web/templates/dnp_entry/show.html.slime index a672573a..31b893ea 100644 --- a/lib/philomena_web/templates/dnp_entry/show.html.slime +++ b/lib/philomena_web/templates/dnp_entry/show.html.slime @@ -6,9 +6,9 @@ h2 .block__header span.block__header__title DNP Information = if can?(@conn, :edit, @dnp_entry) do - = link "Edit listing", to: Routes.dnp_entry_path(@conn, :edit, @dnp_entry, tag_id: @dnp_entry.tag_id) + = link "Edit listing", to: ~p"/dnp/#{@dnp_entry}/edit?#{[tag_id: @dnp_entry.tag_id]}" - = link "Back to DNP List", to: Routes.dnp_entry_path(@conn, :index) + = link "Back to DNP List", to: ~p"/dnp" .block__content table.table @@ -53,26 +53,26 @@ h2 = if can?(@conn, :index, Philomena.DnpEntries.DnpEntry) do = case @dnp_entry.aasm_state do - s when s in ["requested", "claimed"] -> - => link "Claim", to: Routes.admin_dnp_entry_transition_path(@conn, :create, @dnp_entry, state: "claimed"), data: [method: "post", confirm: "Are you really, really sure?"] + => link "Claim", to: ~p"/admin/dnp_entries/#{@dnp_entry}/transition?#{[state: "claimed"]}", data: [method: "post", confirm: "Are you really, really sure?"] ' • - => link "Approve", to: Routes.admin_dnp_entry_transition_path(@conn, :create, @dnp_entry, state: "listed"), data: [method: "post", confirm: "Are you really, really sure?"] + => link "Approve", to: ~p"/admin/dnp_entries/#{@dnp_entry}/transition?#{[state: "listed"]}", data: [method: "post", confirm: "Are you really, really sure?"] ' • - => link "Close", to: Routes.admin_dnp_entry_transition_path(@conn, :create, @dnp_entry, state: "closed"), data: [method: "post", confirm: "Are you really, really sure?"] + => link "Close", to: ~p"/admin/dnp_entries/#{@dnp_entry}/transition?#{[state: "closed"]}", data: [method: "post", confirm: "Are you really, really sure?"] - "listed" -> - => link "Rescind", to: Routes.admin_dnp_entry_transition_path(@conn, :create, @dnp_entry, state: "rescinded"), data: [method: "post", confirm: "Are you really, really sure?"] + => link "Rescind", to: ~p"/admin/dnp_entries/#{@dnp_entry}/transition?#{[state: "rescinded"]}", data: [method: "post", confirm: "Are you really, really sure?"] ' • - = link "Close", to: Routes.admin_dnp_entry_transition_path(@conn, :create, @dnp_entry, state: "closed"), data: [method: "post", confirm: "Are you really, really sure?"] + = link "Close", to: ~p"/admin/dnp_entries/#{@dnp_entry}/transition?#{[state: "closed"]}", data: [method: "post", confirm: "Are you really, really sure?"] - s when s in ["rescinded", "acknowledged"] -> - => link "Claim", to: Routes.admin_dnp_entry_transition_path(@conn, :create, @dnp_entry, state: "acknowledged"), data: [method: "post", confirm: "Are you really, really sure?"] + => link "Claim", to: ~p"/admin/dnp_entries/#{@dnp_entry}/transition?#{[state: "acknowledged"]}", data: [method: "post", confirm: "Are you really, really sure?"] ' • - = link "Close", to: Routes.admin_dnp_entry_transition_path(@conn, :create, @dnp_entry, state: "closed"), data: [method: "post", confirm: "Are you really, really sure?"] + = link "Close", to: ~p"/admin/dnp_entries/#{@dnp_entry}/transition?#{[state: "closed"]}", data: [method: "post", confirm: "Are you really, really sure?"] - _state -> - => link "Claim", to: Routes.admin_dnp_entry_transition_path(@conn, :create, @dnp_entry, state: "claimed"), data: [method: "post", confirm: "Are you really, really sure?"] + => link "Claim", to: ~p"/admin/dnp_entries/#{@dnp_entry}/transition?#{[state: "claimed"]}", data: [method: "post", confirm: "Are you really, really sure?"] = if assigns[:mod_notes] do h4 Mod Notes = render PhilomenaWeb.Admin.ModNoteView, "_table.html", mod_notes: @mod_notes, conn: @conn - = link "Add New Note", to: Routes.admin_mod_note_path(@conn, :new, notable_id: @dnp_entry.id, notable_type: "DnpEntry") + = link "Add New Note", to: ~p"/admin/mod_notes/new?#{[notable_id: @dnp_entry.id, notable_type: "DnpEntry"]}" diff --git a/lib/philomena_web/templates/duplicate_report/_form.html.slime b/lib/philomena_web/templates/duplicate_report/_form.html.slime index 128de57b..19d1ec64 100644 --- a/lib/philomena_web/templates/duplicate_report/_form.html.slime +++ b/lib/philomena_web/templates/duplicate_report/_form.html.slime @@ -1,4 +1,4 @@ -= form_for @changeset, Routes.duplicate_report_path(@conn, :create), fn f -> += form_for @changeset, ~p"/duplicate_reports", fn f -> = hidden_input f, :image_id, value: @image.id .field ' Delete this image and redirect to diff --git a/lib/philomena_web/templates/duplicate_report/_image_cell.html.slime b/lib/philomena_web/templates/duplicate_report/_image_cell.html.slime index 1e262a35..9e52462c 100644 --- a/lib/philomena_web/templates/duplicate_report/_image_cell.html.slime +++ b/lib/philomena_web/templates/duplicate_report/_image_cell.html.slime @@ -18,12 +18,12 @@ = if can?(@conn, :edit, @report) and mergeable?(@report) do = if @source do - a href=Routes.duplicate_report_accept_reverse_path(@conn, :create, @report) data-method="post" + a href=~p"/duplicate_reports/#{@report}/accept_reverse" data-method="post" button.button ' Keep Source i.fa.fa-arrow-left - else - a href=Routes.duplicate_report_accept_path(@conn, :create, @report) data-method="post" + a href=~p"/duplicate_reports/#{@report}/accept" data-method="post" button.button i.fa.fa-arrow-right> | Keep Target diff --git a/lib/philomena_web/templates/duplicate_report/_list.html.slime b/lib/philomena_web/templates/duplicate_report/_list.html.slime index 87de9fc0..bb18bb50 100644 --- a/lib/philomena_web/templates/duplicate_report/_list.html.slime +++ b/lib/philomena_web/templates/duplicate_report/_list.html.slime @@ -15,7 +15,7 @@ tr = if same_aspect_ratio?(report) do td.success - a href=Routes.duplicate_report_path(@conn, :show, report) + a href=~p"/duplicate_reports/#{report}" ' Visual diff | (Same aspect ratio) @@ -139,13 +139,13 @@ = if can?(@conn, :edit, report) do div = if report.state == "open" do - a href=(Routes.duplicate_report_claim_path(@conn, :create, report) <> "#report_options_#{report.id}") data-method="post" + a href=(~p"/duplicate_reports/#{report}/claim" <> "#report_options_#{report.id}") data-method="post" button.button.button--separate-right i.fa.fa-clipboard> ' Claim = if report.state != "rejected" do - a href=Routes.duplicate_report_reject_path(@conn, :create, report) data-method="post" + a href=~p"/duplicate_reports/#{report}/reject" data-method="post" button.button i.fa.fa-times> ' Reject @@ -157,6 +157,6 @@ = if report.user do ' by - =< link report.user.name, to: Routes.profile_path(@conn, :show, report.user) + =< link report.user.name, to: ~p"/profiles/#{report.user}" = escape_nl2br(report.reason) diff --git a/lib/philomena_web/templates/duplicate_report/index.html.slime b/lib/philomena_web/templates/duplicate_report/index.html.slime index b29595f7..ef46cf6a 100644 --- a/lib/philomena_web/templates/duplicate_report/index.html.slime +++ b/lib/philomena_web/templates/duplicate_report/index.html.slime @@ -1,6 +1,6 @@ h1 Duplicate Reports -- route = fn p -> Routes.duplicate_report_path(@conn, :index, p) end +- route = fn p -> ~p"/duplicate_reports?#{p}" end - pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @duplicate_reports, route: route, conn: @conn, params: [states: @conn.params["states"] || ["open", "claimed"]] .block @@ -8,14 +8,14 @@ h1 Duplicate Reports .page__pagination = pagination .page__info span.block__header__title Display only: - => link "Open (All)", to: Routes.duplicate_report_path(@conn, :index, states: ~W(open claimed)) - => link "Open (Unclaimed)", to: Routes.duplicate_report_path(@conn, :index, states: ~W(open)) - => link "Open (Claimed)", to: Routes.duplicate_report_path(@conn, :index, states: ~W(claimed)) - => link "Open + Rejected", to: Routes.duplicate_report_path(@conn, :index, states: ~W(open rejected)) - => link "Rejected", to: Routes.duplicate_report_path(@conn, :index, states: ~W(rejected)) - => link "Rejected + Accepted", to: Routes.duplicate_report_path(@conn, :index, states: ~W(rejected accepted)) - => link "Accepted", to: Routes.duplicate_report_path(@conn, :index, states: ~W(accepted)) - = link "All", to: Routes.duplicate_report_path(@conn, :index, states: ~W(open rejected accepted claimed)) + => link "Open (All)", to: ~p"/duplicate_reports?#{[states: ~W(open claimed)]}" + => link "Open (Unclaimed)", to: ~p"/duplicate_reports?#{[states: ~W(open)]}" + => link "Open (Claimed)", to: ~p"/duplicate_reports?#{[states: ~W(claimed)]}" + => link "Open + Rejected", to: ~p"/duplicate_reports?#{[states: ~W(open rejected)]}" + => link "Rejected", to: ~p"/duplicate_reports?#{[states: ~W(rejected)]}" + => link "Rejected + Accepted", to: ~p"/duplicate_reports?#{[states: ~W(rejected accepted)]}" + => link "Accepted", to: ~p"/duplicate_reports?#{[states: ~W(accepted)]}" + = link "All", to: ~p"/duplicate_reports?#{[states: ~W(open rejected accepted claimed)]}" = render PhilomenaWeb.DuplicateReportView, "_list.html", duplicate_reports: @duplicate_reports, conn: @conn diff --git a/lib/philomena_web/templates/filter/_filter.html.slime b/lib/philomena_web/templates/filter/_filter.html.slime index 859608f7..ab4e9260 100644 --- a/lib/philomena_web/templates/filter/_filter.html.slime +++ b/lib/philomena_web/templates/filter/_filter.html.slime @@ -20,20 +20,20 @@ = length(@filter.hidden_tag_ids) li - = link "View this filter", to: Routes.filter_path(@conn, :show, @filter), class: "button" + = link "View this filter", to: ~p"/filters/#{@filter}", class: "button" li - = link "Copy and Customize", to: Routes.filter_path(@conn, :new, based_on: @filter), class: "button" + = link "Copy and Customize", to: ~p"/filters/new?#{[based_on: @filter]}", class: "button" = if can?(@conn, :edit, @filter) do li - = link "Edit this filter", to: Routes.filter_path(@conn, :edit, @filter), class: "button" + = link "Edit this filter", to: ~p"/filters/#{@filter}/edit", class: "button" = if @filter.id == @conn.assigns.current_filter.id do li strong Your current filter - else li - = button_to "Use this filter", Routes.filter_current_path(@conn, :update, id: @filter), method: "put", class: "button" + = button_to "Use this filter", ~p"/filters/current?#{[id: @filter]}", method: "put", class: "button" p em = @filter.description diff --git a/lib/philomena_web/templates/filter/edit.html.slime b/lib/philomena_web/templates/filter/edit.html.slime index 4ec94253..db0bf5d6 100644 --- a/lib/philomena_web/templates/filter/edit.html.slime +++ b/lib/philomena_web/templates/filter/edit.html.slime @@ -1,5 +1,5 @@ h2 Editing Filter -= render PhilomenaWeb.FilterView, "_form.html", filter: @changeset, route: Routes.filter_path(@conn, :update, @filter) += render PhilomenaWeb.FilterView, "_form.html", filter: @changeset, route: ~p"/filters/#{@filter}" = if not @filter.public and not @filter.system do br @@ -19,4 +19,4 @@ h2 Editing Filter strong irreversible ' . Once you make a filter public, you cannot make it private again. - = button_to "Convert to Public Filter", Routes.filter_public_path(@conn, :create, @filter), class: "button", method: "create", data: [confirm: "Are you really, really sure?"] + = button_to "Convert to Public Filter", ~p"/filters/#{@filter}/public", class: "button", method: "create", data: [confirm: "Are you really, really sure?"] diff --git a/lib/philomena_web/templates/filter/index.html.slime b/lib/philomena_web/templates/filter/index.html.slime index 1598658f..3474b6fb 100644 --- a/lib/philomena_web/templates/filter/index.html.slime +++ b/lib/philomena_web/templates/filter/index.html.slime @@ -28,7 +28,7 @@ h2 My Filters = if @current_user do p - = link("Click here to make a new filter from scratch", to: Routes.filter_path(@conn, :new)) + = link("Click here to make a new filter from scratch", to: ~p"/filters/new") = for filter <- @my_filters do = render PhilomenaWeb.FilterView, "_filter.html", conn: @conn, filter: filter - else @@ -43,12 +43,12 @@ h2 Recent Filters p ' Clicking this button will clear the recent filters list in the header dropdown. - = button_to "Clear recent filter list", Routes.filter_clear_recent_path(@conn, :delete), method: "delete", class: "button" + = button_to "Clear recent filter list", ~p"/filters/clear_recent", method: "delete", class: "button" h2 Search Filters p ' Some users maintain custom filters which are publicly shared; you can search these filters with the box below. - = form_for :filters, Routes.filter_path(@conn, :index), [method: "get", class: "hform", enforce_utf8: false], fn f -> + = form_for :filters, ~p"/filters", [method: "get", class: "hform", enforce_utf8: false], fn f -> .field = text_input f, :fq, name: :fq, value: @conn.params["fq"], class: "input hform__text", placeholder: "Search filters", autocapitalize: "none" = submit "Search", class: "hform__button button" @@ -62,7 +62,7 @@ h2 Search Results = cond do - Enum.any?(@filters) -> - - route = fn p -> Routes.filter_path(@conn, :index, p) end + - route = fn p -> ~p"/filters?#{p}" end - pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @filters, route: route, params: [fq: @conn.params["fq"]], conn: @conn = for filter <- @filters do @@ -99,49 +99,49 @@ table.table td Literal td Matches the creator of this filter. td - code = link "creator:AppleDash", to: Routes.filter_path(@conn, :index, fq: "creator:AppleDash") + code = link "creator:AppleDash", to: ~p"/filters?#{[fq: "creator:AppleDash"]}" tr td code name td Literal td Matches the name of this filter. This is the default field. td - code = link "name:default", to: Routes.filter_path(@conn, :index, fq: "name:default") + code = link "name:default", to: ~p"/filters?#{[fq: "name:default"]}" tr td code description td Full Text td Matches the description of this filter. td - code = link "description:the show's rating", to: Routes.filter_path(@conn, :index, fq: "description:the show's rating") + code = link "description:the show's rating", to: ~p"/filters?#{[fq: "description:the show's rating"]}" tr td code created_at td Date/Time Range td Matches the creation time of this filter. td - code = link "created_at:2015", to: Routes.filter_path(@conn, :index, fq: "created_at:2015") + code = link "created_at:2015", to: ~p"/filters?#{[fq: "created_at:2015"]}" tr td code id td Numeric Range td Matches the numeric surrogate key for this filter. td - code = link "id:1", to: Routes.filter_path(@conn, :index, fq: "id:1") + code = link "id:1", to: ~p"/filters?#{[fq: "id:1"]}" tr td code spoilered_count td Numeric Range td Matches the number of spoilered tags in this filter. td - code = link "spoilered_count:1", to: Routes.filter_path(@conn, :index, fq: "spoilered_count:1") + code = link "spoilered_count:1", to: ~p"/filters?#{[fq: "spoilered_count:1"]}" tr td code hidden_count td Numeric Range td Matches the number of hidden tags in this filter. td - code = link "hidden_count:1", to: Routes.filter_path(@conn, :index, fq: "hidden_count:1") + code = link "hidden_count:1", to: ~p"/filters?#{[fq: "hidden_count:1"]}" tr td code my @@ -150,14 +150,14 @@ table.table code> my:filters ' matches filters you have published if you are signed in. td - code = link "my:filters", to: Routes.filter_path(@conn, :index, fq: "my:filters") + code = link "my:filters", to: ~p"/filters?#{[fq: "my:filters"]}" tr td code system td Boolean td Matches system filters td - code = link "system:true", to: Routes.filter_path(@conn, :index, fq: "system:true") + code = link "system:true", to: ~p"/filters?#{[fq: "system:true"]}" tr td code public @@ -167,14 +167,14 @@ table.table code> public:false ' matches only your own private filters. td - code = link "public:false", to: Routes.filter_path(@conn, :index, fq: "public:false") + code = link "public:false", to: ~p"/filters?#{[fq: "public:false"]}" tr td code user_id td Literal td Matches filters with the specified user_id. td - code = link "user_id:307505", to: Routes.filter_path(@conn, :index, fq: "user_id:307505") + code = link "user_id:307505", to: ~p"/filters?#{[fq: "user_id:307505"]}" = if @conn.params["fq"] do - p = link("Back to filters", to: Routes.filter_path(@conn, :index)) + p = link("Back to filters", to: ~p"/filters") diff --git a/lib/philomena_web/templates/filter/new.html.slime b/lib/philomena_web/templates/filter/new.html.slime index de881073..26dc5513 100644 --- a/lib/philomena_web/templates/filter/new.html.slime +++ b/lib/philomena_web/templates/filter/new.html.slime @@ -1,2 +1,2 @@ h2 Creating New Filter -= render PhilomenaWeb.FilterView, "_form.html", filter: @changeset, route: Routes.filter_path(@conn, :create) \ No newline at end of file += render PhilomenaWeb.FilterView, "_form.html", filter: @changeset, route: ~p"/filters" \ No newline at end of file diff --git a/lib/philomena_web/templates/filter/show.html.slime b/lib/philomena_web/templates/filter/show.html.slime index 15608482..6e1221f3 100644 --- a/lib/philomena_web/templates/filter/show.html.slime +++ b/lib/philomena_web/templates/filter/show.html.slime @@ -18,14 +18,14 @@ h1 strong Your current filter - else li - = button_to "Use this filter", Routes.filter_current_path(@conn, :update, id: @filter), method: "put", class: "button" + = button_to "Use this filter", ~p"/filters/current?#{[id: @filter]}", method: "put", class: "button" = if can?(@conn, :edit, @filter) do li - = link "Edit this filter", to: Routes.filter_path(@conn, :edit, @filter), class: "button" + = link "Edit this filter", to: ~p"/filters/#{@filter}/edit", class: "button" = if can?(@conn, :delete, @filter) do - = button_to "Destroy this filter", Routes.filter_path(@conn, :delete, @filter), method: "delete", class: "button", data: [confirm: "Are you really, really sure?"] + = button_to "Destroy this filter", ~p"/filters/#{@filter}", method: "delete", class: "button", data: [confirm: "Are you really, really sure?"] = if @filter.user do p.filter-maintainer @@ -61,4 +61,4 @@ h1 /p = link("Report filter to moderators", new_report_path(reportable_class: 'filter', reportable_id: @filter.id) -p = link("Back to filters", to: Routes.filter_path(@conn, :index)) +p = link("Back to filters", to: ~p"/filters") diff --git a/lib/philomena_web/templates/fingerprint_profile/show.html.slime b/lib/philomena_web/templates/fingerprint_profile/show.html.slime index dae6b6a2..cfb36e1e 100644 --- a/lib/philomena_web/templates/fingerprint_profile/show.html.slime +++ b/lib/philomena_web/templates/fingerprint_profile/show.html.slime @@ -3,24 +3,24 @@ h1 ' 's fingerprint profile ul - li = link "View images this fingerprint has uploaded", to: Routes.search_path(@conn, :index, q: "fingerprint:#{@fingerprint}") - li = link "View comments this fingerprint has posted", to: Routes.comment_path(@conn, :index, cq: "fingerprint:#{@fingerprint}") - li = link "View posts this fingerprint has made", to: Routes.post_path(@conn, :index, pq: "fingerprint:#{@fingerprint}") + li = link "View images this fingerprint has uploaded", to: ~p"/search?#{[q: "fingerprint:#{@fingerprint}"]}" + li = link "View comments this fingerprint has posted", to: ~p"/comments?#{[cq: "fingerprint:#{@fingerprint}"]}" + li = link "View posts this fingerprint has made", to: ~p"/posts?#{[pq: "fingerprint:#{@fingerprint}"]}" = render PhilomenaWeb.BanView, "_bans.html", bans: @fingerprint_bans, conn: @conn h2 Administration Options ul - li = link "View tag changes", to: Routes.fingerprint_profile_tag_change_path(@conn, :index, @fingerprint) - li = link "View source URL history", to: Routes.fingerprint_profile_source_change_path(@conn, :index, @fingerprint) - li = link "View reports this fingerprint has made", to: Routes.admin_report_path(@conn, :index, rq: "fingerprint:#{@fingerprint}") - li = link "View fingerprint ban history", to: Routes.admin_fingerprint_ban_path(@conn, :index, fingerprint: @fingerprint) - li = link "Ban this sucker", to: Routes.admin_fingerprint_ban_path(@conn, :new, fingerprint: @fingerprint) + li = link "View tag changes", to: ~p"/fingerprint_profiles/#{@fingerprint}/tag_changes" + li = link "View source URL history", to: ~p"/fingerprint_profiles/#{@fingerprint}/source_changes" + li = link "View reports this fingerprint has made", to: ~p"/admin/reports?#{[rq: "fingerprint:#{@fingerprint}"]}" + li = link "View fingerprint ban history", to: ~p"/admin/fingerprint_bans?#{[fingerprint: @fingerprint]}" + li = link "Ban this sucker", to: ~p"/admin/fingerprint_bans/new?#{[fingerprint: @fingerprint]}" h2 Actions ul - li = link "Revert all tag changes", to: Routes.tag_change_full_revert_path(@conn, :create, [fingerprint: @fingerprint]), data: [confirm: "Are you really, really sure?", method: "create"] - li = link "...the button above didn't work (use carefully, this is resource-intensive)", to: Routes.tag_change_full_revert_path(@conn, :create, [fingerprint: @fingerprint, batch_size: 1]), data: [confirm: "Please confirm that you're aware that this may crash the site and are ready to take on the full wrath of the admins if it does so after you press this button.", method: "create"] + li = link "Revert all tag changes", to: ~p"/tag_changes/full_revert?#{[fingerprint: @fingerprint]}", data: [confirm: "Are you really, really sure?", method: "create"] + li = link "...the button above didn't work (use carefully, this is resource-intensive)", to: ~p"/tag_changes/full_revert?#{[fingerprint: @fingerprint, batch_size: 1]}", data: [confirm: "Please confirm that you're aware that this may crash the site and are ready to take on the full wrath of the admins if it does so after you press this button.", method: "create"] h4 Observed users table.table @@ -34,7 +34,7 @@ table.table = for ufp <- @user_fps do tr td - = link ufp.user.name, to: Routes.profile_path(@conn, :show, ufp.user) + = link ufp.user.name, to: ~p"/profiles/#{ufp.user}" td => ufp.uses ' times diff --git a/lib/philomena_web/templates/fingerprint_profile/source_change/index.html.slime b/lib/philomena_web/templates/fingerprint_profile/source_change/index.html.slime index d1dd1440..0c92e88d 100644 --- a/lib/philomena_web/templates/fingerprint_profile/source_change/index.html.slime +++ b/lib/philomena_web/templates/fingerprint_profile/source_change/index.html.slime @@ -2,7 +2,7 @@ h1 ' Source changes by = @fingerprint -- route = fn p -> Routes.fingerprint_profile_source_change_path(@conn, :index, @fingerprint, p) end +- route = fn p -> ~p"/fingerprint_profiles/#{@fingerprint}/source_changes?#{p}" end - pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @source_changes, route: route, conn: @conn = render PhilomenaWeb.SourceChangeView, "index.html", conn: @conn, source_changes: @source_changes, pagination: pagination diff --git a/lib/philomena_web/templates/fingerprint_profile/tag_change/index.html.slime b/lib/philomena_web/templates/fingerprint_profile/tag_change/index.html.slime index dd2b50ac..9a486e91 100644 --- a/lib/philomena_web/templates/fingerprint_profile/tag_change/index.html.slime +++ b/lib/philomena_web/templates/fingerprint_profile/tag_change/index.html.slime @@ -2,7 +2,7 @@ h1 ' Tag changes by = @fingerprint -- route = fn p -> Routes.fingerprint_profile_tag_change_path(@conn, :index, @fingerprint, p) end +- route = fn p -> ~p"/fingerprint_profiles/#{@fingerprint}/tag_changes?#{p}" end - params = if @conn.params["added"], do: [added: @conn.params["added"]] - pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @tag_changes, route: route, conn: @conn, params: params @@ -11,8 +11,8 @@ h1 span.block__header__title | Display only: - = link "Removed", to: Routes.fingerprint_profile_tag_change_path(@conn, :index, @fingerprint, added: 0) - = link "Added", to: Routes.fingerprint_profile_tag_change_path(@conn, :index, @fingerprint, added: 1) - = link "All", to: Routes.fingerprint_profile_tag_change_path(@conn, :index, @fingerprint) + = link "Removed", to: ~p"/fingerprint_profiles/#{@fingerprint}/tag_changes?#{[added: 0]}" + = link "Added", to: ~p"/fingerprint_profiles/#{@fingerprint}/tag_changes?#{[added: 1]}" + = link "All", to: ~p"/fingerprint_profiles/#{@fingerprint}/tag_changes" = render PhilomenaWeb.TagChangeView, "index.html", conn: @conn, tag_changes: @tag_changes, pagination: pagination diff --git a/lib/philomena_web/templates/forum/index.html.slime b/lib/philomena_web/templates/forum/index.html.slime index 3eaa978d..616376fc 100644 --- a/lib/philomena_web/templates/forum/index.html.slime +++ b/lib/philomena_web/templates/forum/index.html.slime @@ -1,7 +1,7 @@ h1 Discussion Forums .block .block__header - a href=Routes.post_path(@conn, :index) + a href=~p"/posts" i.fa.fa-fw.fa-search> ' Search Posts span.block__header__item @@ -19,16 +19,16 @@ h1 Discussion Forums = for forum <- @forums do tr td.table--communication-list__name - => link(forum.name, to: Routes.forum_path(@conn, :show, forum)) + => link(forum.name, to: ~p"/forums/#{forum}") .small-text = forum.description td.table--communication-list__stats.hide-mobile = forum.topic_count td.table--communication-list__stats.hide-mobile = forum.post_count td.table--communication-list__last-post = if forum.last_post do strong - => link(forum.last_post.topic.title, to: Routes.forum_topic_path(@conn, :show, forum.last_post.topic.forum, forum.last_post.topic)) + => link(forum.last_post.topic.title, to: ~p"/forums/#{forum.last_post.topic.forum}/topics/#{forum.last_post.topic}") br - => link("Go to post", to: Routes.forum_topic_path(@conn, :show, forum.last_post.topic.forum, forum.last_post.topic, post_id: forum.last_post.id) <> "#post_#{forum.last_post.id}") + => link("Go to post", to: ~p"/forums/#{forum.last_post.topic.forum}/topics/#{forum.last_post.topic}?#{[post_id: forum.last_post.id]}" <> "#post_#{forum.last_post.id}") ' by => render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: forum.last_post, conn: @conn br diff --git a/lib/philomena_web/templates/forum/show.html.slime b/lib/philomena_web/templates/forum/show.html.slime index 23a6c676..870427ff 100644 --- a/lib/philomena_web/templates/forum/show.html.slime +++ b/lib/philomena_web/templates/forum/show.html.slime @@ -1,16 +1,16 @@ -- pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @topics, route: fn p -> Routes.forum_path(@conn, :show, @forum, p) end +- pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @topics, route: fn p -> ~p"/forums/#{@forum}?#{p}" end h1 = @forum.name .block .block__header - => link("Forums", to: Routes.forum_path(@conn, :index)) + => link("Forums", to: ~p"/forums") ' » - => link(@forum.name, to: Routes.forum_path(@conn, :show, @forum)) - a href=Routes.forum_topic_path(@conn, :new, @forum) + => link(@forum.name, to: ~p"/forums/#{@forum}") + a href=~p"/forums/#{@forum}/topics/new" i.fa.fa-fw.fa-edit> ' New Topic - a href=Routes.post_path(@conn, :index, pq: "forum:#{@forum.short_name}") + a href=~p"/posts?#{[pq: "forum:#{@forum.short_name}"]}" i.fa.fa-fw.fa-search> ' Search Posts span.spacing-left @@ -38,7 +38,7 @@ h1 = @forum.name i.fa.fa-lock = if topic.poll do i.fas.fa-poll-h - =< link(topic.title, to: Routes.forum_topic_path(@conn, :show, @forum, topic)) + =< link(topic.title, to: ~p"/forums/#{@forum}/topics/#{topic}") .small-text ' Posted => pretty_time(topic.created_at) @@ -47,7 +47,7 @@ h1 = @forum.name td.table--communication-list__stats.hide-mobile = topic.post_count td.table--communication-list__last-post = if topic.last_post do - => link("Go to post", to: Routes.forum_topic_path(@conn, :show, topic.forum, topic, post_id: topic.last_post) <> "#post_#{topic.last_post.id}") + => link("Go to post", to: ~p"/forums/#{topic.forum}/topics/#{topic}?#{[post_id: topic.last_post]}" <> "#post_#{topic.last_post.id}") ' by = render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: topic.last_post, conn: @conn br diff --git a/lib/philomena_web/templates/forum/subscription/_subscription.html.slime b/lib/philomena_web/templates/forum/subscription/_subscription.html.slime index f71096cd..42172150 100644 --- a/lib/philomena_web/templates/forum/subscription/_subscription.html.slime +++ b/lib/philomena_web/templates/forum/subscription/_subscription.html.slime @@ -1,8 +1,8 @@ elixir: - watch_path = Routes.forum_subscription_path(@conn, :create, @forum) + watch_path = ~p"/forums/#{@forum}/subscription" watch_class = if @watching, do: "hidden", else: "" - unwatch_path = Routes.forum_subscription_path(@conn, :delete, @forum) + unwatch_path = ~p"/forums/#{@forum}/subscription" unwatch_class = if @watching, do: "", else: "hidden" = if @conn.assigns.current_user do @@ -17,7 +17,7 @@ elixir: span.hide-mobile ' Unsubscribe - else - a href=Routes.session_path(@conn, :new) + a href=~p"/sessions/new" i.fa.fa-bell> span.hide-mobile ' Subscribe diff --git a/lib/philomena_web/templates/gallery/_gallery.html.slime b/lib/philomena_web/templates/gallery/_gallery.html.slime index d7c18a80..60ae2d56 100644 --- a/lib/philomena_web/templates/gallery/_gallery.html.slime +++ b/lib/philomena_web/templates/gallery/_gallery.html.slime @@ -1,4 +1,4 @@ -- link = Routes.gallery_path(@conn, :show, @gallery) +- link = ~p"/galleries/#{@gallery}" .media-box a.media-box__header.media-box__header--link href=link title=@gallery.title diff --git a/lib/philomena_web/templates/gallery/edit.html.slime b/lib/philomena_web/templates/gallery/edit.html.slime index fe0fc4af..80687435 100644 --- a/lib/philomena_web/templates/gallery/edit.html.slime +++ b/lib/philomena_web/templates/gallery/edit.html.slime @@ -1,3 +1,3 @@ h1 Editing Gallery -= render PhilomenaWeb.GalleryView, "_form.html", conn: @conn, changeset: @changeset, action: Routes.gallery_path(@conn, :update, @gallery) \ No newline at end of file += render PhilomenaWeb.GalleryView, "_form.html", conn: @conn, changeset: @changeset, action: ~p"/galleries/#{@gallery}" \ No newline at end of file diff --git a/lib/philomena_web/templates/gallery/index.html.slime b/lib/philomena_web/templates/gallery/index.html.slime index 15b5312d..9750364c 100644 --- a/lib/philomena_web/templates/gallery/index.html.slime +++ b/lib/philomena_web/templates/gallery/index.html.slime @@ -1,5 +1,5 @@ elixir: - route = fn p -> Routes.gallery_path(@conn, :index, p) end + route = fn p -> ~p"/galleries?#{p}" end pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @galleries, route: route, params: [gallery: @conn.params["gallery"]] .column-layout @@ -8,7 +8,7 @@ elixir: .block__content h3 Search Galleries - = form_for @conn, Routes.gallery_path(@conn, :index), [as: :gallery, method: "get", class: "hform"], fn f -> + = form_for @conn, ~p"/galleries", [as: :gallery, method: "get", class: "hform"], fn f -> .field = label f, :title, "Title" .field = text_input f, :title, class: "input hform__text", placeholder: "Gallery title (* as wildcard)" diff --git a/lib/philomena_web/templates/gallery/new.html.slime b/lib/philomena_web/templates/gallery/new.html.slime index 7a555f67..3aa4a7f3 100644 --- a/lib/philomena_web/templates/gallery/new.html.slime +++ b/lib/philomena_web/templates/gallery/new.html.slime @@ -1,3 +1,3 @@ h1 Create a Gallery -= render PhilomenaWeb.GalleryView, "_form.html", conn: @conn, changeset: @changeset, action: Routes.gallery_path(@conn, :create) \ No newline at end of file += render PhilomenaWeb.GalleryView, "_form.html", conn: @conn, changeset: @changeset, action: ~p"/galleries" \ No newline at end of file diff --git a/lib/philomena_web/templates/gallery/show.html.slime b/lib/philomena_web/templates/gallery/show.html.slime index 63ad508b..3c61643a 100644 --- a/lib/philomena_web/templates/gallery/show.html.slime +++ b/lib/philomena_web/templates/gallery/show.html.slime @@ -1,7 +1,7 @@ elixir: scope = scope(@conn) - image_url = fn image, hit -> Routes.image_path(@conn, :show, image, Keyword.put(scope, :sort, hit["sort"])) end - route = fn p -> Routes.gallery_path(@conn, :show, @gallery, p) end + image_url = fn image, hit -> ~p"/images/#{image}?#{Keyword.put(scope, :sort, hit["sort"])}" end + route = fn p -> ~p"/galleries/#{@gallery}?#{p}" end pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @images, route: route, params: scope info = render PhilomenaWeb.PaginationView, "_pagination_info.html", page: @images @@ -19,12 +19,12 @@ elixir: .flex__right.page__options = render PhilomenaWeb.ImageView, "_random_button.html", conn: @conn, params: scope - a href=Routes.gallery_report_path(@conn, :new, @gallery) + a href=~p"/galleries/#{@gallery}/reports/new" i.fa.fa-exclamation-triangle> span.hide-mobile Report = if can?(@conn, :edit, @gallery) do - a href=Routes.gallery_path(@conn, :edit, @gallery) + a href=~p"/galleries/#{@gallery}/edit" i.fas.fa-edit> span.hide-mobile Edit @@ -33,11 +33,11 @@ elixir: i.fa.fa-sort> ' Rearrange - a.rearrange-button.js-save.hidden href="#" data-click-hide=".js-save,#gallery-rearrange-info" data-click-show=".js-rearrange" data-reorder-path=Routes.gallery_order_path(@conn, :update, @gallery) + a.rearrange-button.js-save.hidden href="#" data-click-hide=".js-save,#gallery-rearrange-info" data-click-show=".js-rearrange" data-reorder-path=~p"/galleries/#{@gallery}/order" i.fa.fa-check> ' Save - a href=Routes.gallery_path(@conn, :delete, @gallery) data-method="delete" data-confirm="Are you really, really sure?" + a href=~p"/galleries/#{@gallery}" data-method="delete" data-confirm="Are you really, really sure?" i.fa.fa-trash> span.hide-mobile Delete @@ -47,7 +47,7 @@ elixir: .block__header.block__header--light.block__header--sub span.block__header__title A gallery by - => link @gallery.creator.name, to: Routes.profile_path(@conn, :show, @gallery.creator) + => link @gallery.creator.name, to: ~p"/profiles/#{@gallery.creator}" ' with => @gallery.image_count = pluralize("image", "images", @gallery.image_count) diff --git a/lib/philomena_web/templates/gallery/subscription/_subscription.html.slime b/lib/philomena_web/templates/gallery/subscription/_subscription.html.slime index b6c5d895..cf40adf9 100644 --- a/lib/philomena_web/templates/gallery/subscription/_subscription.html.slime +++ b/lib/philomena_web/templates/gallery/subscription/_subscription.html.slime @@ -1,8 +1,8 @@ elixir: - watch_path = Routes.gallery_subscription_path(@conn, :create, @gallery) + watch_path = ~p"/galleries/#{@gallery}/subscription" watch_class = if @watching, do: "hidden", else: "" - unwatch_path = Routes.gallery_subscription_path(@conn, :delete, @gallery) + unwatch_path = ~p"/galleries/#{@gallery}/subscription" unwatch_class = if @watching, do: "", else: "hidden" = if @conn.assigns.current_user do @@ -17,7 +17,7 @@ elixir: span.hide-mobile ' Unsubscribe - else - a href=Routes.session_path(@conn, :new) + a href=~p"/sessions/new" i.fa.fa-bell> span.hide-mobile ' Subscribe diff --git a/lib/philomena_web/templates/image/_add_to_gallery_dropdown.html.slime b/lib/philomena_web/templates/image/_add_to_gallery_dropdown.html.slime index 3c7b7659..9c5174bb 100644 --- a/lib/philomena_web/templates/image/_add_to_gallery_dropdown.html.slime +++ b/lib/philomena_web/templates/image/_add_to_gallery_dropdown.html.slime @@ -8,7 +8,7 @@ .block .block__content.add-to-gallery-list .block__list - a.block__list__link.primary href=Routes.gallery_path(@conn, :index, gallery: [include_image: @image.id]) + a.block__list__link.primary href=~p"/galleries?#{[gallery: [include_image: @image.id]]}" i.fa.fa-table> span.hide-mobile Featured in @@ -18,24 +18,24 @@ = if present do / Options to remove li id="gallery_#{gallery.id}" - a.block__list__link.js-gallery-add.hidden data-fetchcomplete-hide="#gallery_#{gallery.id} .js-gallery-add" data-fetchcomplete-show="#gallery_#{gallery.id} .js-gallery-remove" data-method="post" data-remote="true" href=Routes.gallery_image_path(@conn, :create, gallery, image_id: @image.id) + a.block__list__link.js-gallery-add.hidden data-fetchcomplete-hide="#gallery_#{gallery.id} .js-gallery-add" data-fetchcomplete-show="#gallery_#{gallery.id} .js-gallery-remove" data-method="post" data-remote="true" href=~p"/galleries/#{gallery}/images?#{[image_id: @image.id]}" = gallery.title - a.block__list__link.active.js-gallery-remove data-fetchcomplete-hide="#gallery_#{gallery.id} .js-gallery-remove" data-fetchcomplete-show="#gallery_#{gallery.id} .js-gallery-add" data-method="delete" data-remote="true" href=Routes.gallery_image_path(@conn, :delete, gallery, image_id: @image.id) + a.block__list__link.active.js-gallery-remove data-fetchcomplete-hide="#gallery_#{gallery.id} .js-gallery-remove" data-fetchcomplete-show="#gallery_#{gallery.id} .js-gallery-add" data-method="delete" data-remote="true" href=~p"/galleries/#{gallery}/images?#{[image_id: @image.id]}" = gallery.title - else / Options to add li id="gallery_#{gallery.id}" - a.block__list__link.js-gallery-add data-fetchcomplete-hide="#gallery_#{gallery.id} .js-gallery-add" data-fetchcomplete-show="#gallery_#{gallery.id} .js-gallery-remove" data-method="post" data-remote="true" href=Routes.gallery_image_path(@conn, :create, gallery, image_id: @image.id) + a.block__list__link.js-gallery-add data-fetchcomplete-hide="#gallery_#{gallery.id} .js-gallery-add" data-fetchcomplete-show="#gallery_#{gallery.id} .js-gallery-remove" data-method="post" data-remote="true" href=~p"/galleries/#{gallery}/images?#{[image_id: @image.id]}" = gallery.title - a.block__list__link.active.js-gallery-remove.hidden data-fetchcomplete-hide="#gallery_#{gallery.id} .js-gallery-remove" data-fetchcomplete-show="#gallery_#{gallery.id} .js-gallery-add" data-method="delete" data-remote="true" href=Routes.gallery_image_path(@conn, :delete, gallery, image_id: @image.id) + a.block__list__link.active.js-gallery-remove.hidden data-fetchcomplete-hide="#gallery_#{gallery.id} .js-gallery-remove" data-fetchcomplete-show="#gallery_#{gallery.id} .js-gallery-add" data-method="delete" data-remote="true" href=~p"/galleries/#{gallery}/images?#{[image_id: @image.id]}" = gallery.title .block__list = if @conn.assigns.current_user do - a.block__list__link.primary href=Routes.gallery_path(@conn, :new, with_image: @image.id) + a.block__list__link.primary href=~p"/galleries/new?#{[with_image: @image.id]}" i.fa.fa-plus> span.hide-limited-desktop.hide-mobile Create a gallery - else - a.block__list__link.primary href=Routes.session_path(@conn, :new) + a.block__list__link.primary href=~p"/sessions/new" i.fa.fa-user-plus> span.hide-limited-desktop.hide-mobile Sign in to create a gallery diff --git a/lib/philomena_web/templates/image/_image_box.html.slime b/lib/philomena_web/templates/image/_image_box.html.slime index e6210860..d8b16dca 100644 --- a/lib/philomena_web/templates/image/_image_box.html.slime +++ b/lib/philomena_web/templates/image/_image_box.html.slime @@ -1,5 +1,5 @@ elixir: - link = assigns[:link] || Routes.image_path(@conn, :show, @image) + link = assigns[:link] || ~p"/images/#{@image}" size_class = case @size do :thumb -> diff --git a/lib/philomena_web/templates/image/_image_container.html.slime b/lib/philomena_web/templates/image/_image_container.html.slime index 1a89d613..a7ecf49d 100644 --- a/lib/philomena_web/templates/image/_image_container.html.slime +++ b/lib/philomena_web/templates/image/_image_container.html.slime @@ -1,4 +1,4 @@ -- link = assigns[:link] || Routes.image_path(@conn, :show, @image) +- link = assigns[:link] || ~p"/images/#{@image}" = image_container @conn, @image, @size, fn -> = cond do diff --git a/lib/philomena_web/templates/image/_image_meta.html.slime b/lib/philomena_web/templates/image/_image_meta.html.slime index 9688ee8c..23c88c19 100644 --- a/lib/philomena_web/templates/image/_image_meta.html.slime +++ b/lib/philomena_web/templates/image/_image_meta.html.slime @@ -1,13 +1,13 @@ .block.block__header .flex.flex--wrap.image-metabar.center--layout id="image_meta_#{@image.id}" .stretched-mobile-links - a.js-prev href=Routes.image_navigate_path(@conn, :index, @image, [rel: "prev"] ++ scope(@conn)) title="Previous Image (j)" + a.js-prev href=~p"/images/#{@image}/navigate?#{[rel: "prev"] ++ scope(@conn)}" title="Previous Image (j)" i.fa.fa-chevron-left - a.js-up href=Routes.image_navigate_path(@conn, :index, @image, [rel: "find"] ++ scope(@conn)) title="Find this image in the global image list (i)" + a.js-up href=~p"/images/#{@image}/navigate?#{[rel: "find"] ++ scope(@conn)}" title="Find this image in the global image list (i)" i.fa.fa-chevron-up - a.js-next href=Routes.image_navigate_path(@conn, :index, @image, [rel: "next"] ++ scope(@conn)) title="Next Image (k)" + a.js-next href=~p"/images/#{@image}/navigate?#{[rel: "next"] ++ scope(@conn)}" title="Next Image (k)" i.fa.fa-chevron-right - a.js-rand href=Routes.image_random_path(@conn, :index, scope(@conn)) title="Random (r)" + a.js-rand href=~p"/images/random?#{scope(@conn)}" title="Random (r)" i.fa.fa-random .stretched-mobile-links a.interaction--fave href="#" rel="nofollow" data-image-id=@image.id @@ -34,7 +34,7 @@ .stretched-mobile-links = render PhilomenaWeb.Image.SubscriptionView, "_subscription.html", watching: @watching, image: @image, conn: @conn = render PhilomenaWeb.ImageView, "_add_to_gallery_dropdown.html", image: @image, user_galleries: @user_galleries, conn: @conn - a href=Routes.image_related_path(@conn, :index, @image) title="Related Images" + a href=~p"/images/#{@image}/related" title="Related Images" i.fa.fa-sitemap> span.hide-limited-desktop.hide-mobile Related .stretched-mobile-links diff --git a/lib/philomena_web/templates/image/_image_target.html.slime b/lib/philomena_web/templates/image/_image_target.html.slime index 3443c74a..fba84b3a 100644 --- a/lib/philomena_web/templates/image/_image_target.html.slime +++ b/lib/philomena_web/templates/image/_image_target.html.slime @@ -8,7 +8,7 @@ p = img_tag(static_path(@conn, "/images/tagblocked.svg"), width: 250, height: 250, data: [click_unfilter: @image.id]) span.filter-explanation - =< link("your current filter", to: Routes.filter_path(@conn, :show, @conn.assigns.current_filter), class: "filter-link") + =< link("your current filter", to: ~p"/filters/#{@conn.assigns.current_filter}", class: "filter-link") ' . = if size == :full and not embed_display do @@ -19,7 +19,7 @@ picture - else .image-show.hidden - a href=Routes.image_path(@conn, :show, @image) title=title_text(@image) + a href=~p"/images/#{@image}" title=title_text(@image) span.imgspoiler - thumb_url = thumb_url(@image, can?(@conn, :show, @image), size) diff --git a/lib/philomena_web/templates/image/_options.html.slime b/lib/philomena_web/templates/image/_options.html.slime index f1514292..a955e063 100644 --- a/lib/philomena_web/templates/image/_options.html.slime +++ b/lib/philomena_web/templates/image/_options.html.slime @@ -2,13 +2,13 @@ #image_options_area .block__header.block__header--js-tabbed - a href="#" data-click-tab="reporting" data-load-tab=Routes.image_reporting_path(@conn, :show, @image) + a href="#" data-click-tab="reporting" data-load-tab=~p"/images/#{@image}/reporting" i.fa.fa-exclamation-triangle> | Report a href="#" data-click-tab="sharing" i.fa.fa-share> | Share - a href="#" data-click-tab="favoriters" data-load-tab=Routes.image_favorite_path(@conn, :index, @image) + a href="#" data-click-tab="favoriters" data-load-tab=~p"/images/#{@image}/favorites" i.fa.fa-star> | List favoriters = if display_mod_tools? and not hide_staff_tools?(@conn) do @@ -56,7 +56,7 @@ | Copy br textarea.input.input--wide.input--separate-top#bbcode_embed_full_tag rows="2" cols="100" readonly="readonly" - = "[img]#{thumb_url(@image, false, :full)}[/img]\n[url=#{Routes.image_url(@conn, :show, @image)}]View on Derpibooru[/url]#{source_link}" + = "[img]#{thumb_url(@image, false, :full)}[/img]\n[url=#{url(~p"/images/#{@image}")}]View on Derpibooru[/url]#{source_link}" p strong> Thumbnailed BBcode a href="#" data-click-copy="#bbcode_embed_thumbnail_tag" @@ -64,11 +64,11 @@ | Copy br textarea.input.input--wide.input--separate-top#bbcode_embed_thumbnail_tag rows="2" cols="100" readonly="readonly" - = "[img]#{thumb_url(@image, false, :medium)}[/img]\n[url=#{Routes.image_url(@conn, :show, @image)}]View on Derpibooru[/url]#{source_link}" + = "[img]#{thumb_url(@image, false, :medium)}[/img]\n[url=#{url(~p"/images/#{@image}")}]View on Derpibooru[/url]#{source_link}" = if display_mod_tools? do .block__tab.hidden data-tab="replace" - = form_for @changeset, Routes.image_file_path(@conn, :update, @image), [method: "put", multipart: true], fn f -> + = form_for @changeset, ~p"/images/#{@image}/file", [method: "put", multipart: true], fn f -> #js-image-upload-previews p Upload a file from your computer .field @@ -85,7 +85,7 @@ .block__tab.hidden data-tab="administration" .block.block--danger - a.button.button--link> href=Routes.image_scratchpad_path(@conn, :edit, @image) + a.button.button--link> href=~p"/images/#{@image}/scratchpad/edit" i.far.fa-edit = if present?(@image.scratchpad) do strong> Mod notes: @@ -94,13 +94,13 @@ em No mod notes present = if not @image.hidden_from_users do - = form_for @changeset, Routes.image_delete_path(@conn, :create, @image), [method: "post"], fn f -> + = form_for @changeset, ~p"/images/#{@image}/delete", [method: "post"], fn f -> = label f, :deletion_reason, "Deletion reason (cannot be empty)" .field.field--inline = text_input f, :deletion_reason, class: "input input--wide", placeholder: "Rule violation", required: true = submit "Delete", class: "button button--state-danger button--separate-left" - else - = form_for @changeset, Routes.image_delete_path(@conn, :update, @image), [method: "put"], fn f -> + = form_for @changeset, ~p"/images/#{@image}/delete", [method: "put"], fn f -> = label f, :deletion_reason, "Deletion reason (cannot be empty)" .field.field--inline = text_input f, :deletion_reason, class: "input input--wide", placeholder: "Rule violation", required: true @@ -108,18 +108,18 @@ .flex.flex--spaced-out.flex--wrap = if not @image.hidden_from_users do - = form_for @changeset, Routes.image_feature_path(@conn, :create, @image), [method: "post"], fn _f -> + = form_for @changeset, ~p"/images/#{@image}/feature", [method: "post"], fn _f -> .field p Marks the image as featured = submit "Feature", data: [confirm: "Are you really, really sure?"], class: "button button--state-success" - else - = button_to "Restore", Routes.image_delete_path(@conn, :delete, @image), method: "delete", class: "button button--state-success" + = button_to "Restore", ~p"/images/#{@image}/delete", method: "delete", class: "button button--state-success" - = form_for @changeset, Routes.image_repair_path(@conn, :create, @image), [method: "post"], fn _f -> + = form_for @changeset, ~p"/images/#{@image}/repair", [method: "post"], fn _f -> .field = submit "Repair", class: "button button--state-success" - = form_for @changeset, Routes.image_hash_path(@conn, :delete, @image), [method: "delete"], fn _f -> + = form_for @changeset, ~p"/images/#{@image}/hash", [method: "delete"], fn _f -> .field p Allows reuploading the image .flex.flex--end-bunched @@ -128,24 +128,24 @@ br .flex.flex--spaced-out = if @image.commenting_allowed do - = button_to "Lock commenting", Routes.image_comment_lock_path(@conn, :create, @image), method: "post", class: "button" + = button_to "Lock commenting", ~p"/images/#{@image}/comment_lock", method: "post", class: "button" - else - = button_to "Unlock commenting", Routes.image_comment_lock_path(@conn, :delete, @image), method: "delete", class: "button" + = button_to "Unlock commenting", ~p"/images/#{@image}/comment_lock", method: "delete", class: "button" = if @image.description_editing_allowed do - = button_to "Lock description editing", Routes.image_description_lock_path(@conn, :create, @image), method: "post", class: "button" + = button_to "Lock description editing", ~p"/images/#{@image}/description_lock", method: "post", class: "button" - else - = button_to "Unlock description editing", Routes.image_description_lock_path(@conn, :delete, @image), method: "delete", class: "button" + = button_to "Unlock description editing", ~p"/images/#{@image}/description_lock", method: "delete", class: "button" = if @image.tag_editing_allowed do - = button_to "Lock tag editing", Routes.image_tag_lock_path(@conn, :create, @image), method: "post", class: "button" + = button_to "Lock tag editing", ~p"/images/#{@image}/tag_lock", method: "post", class: "button" - else - = button_to "Unlock tag editing", Routes.image_tag_lock_path(@conn, :delete, @image), method: "delete", class: "button" + = button_to "Unlock tag editing", ~p"/images/#{@image}/tag_lock", method: "delete", class: "button" br .flex.flex--spaced-out - = link "Lock specific tags", to: Routes.image_tag_lock_path(@conn, :show, @image), class: "button" + = link "Lock specific tags", to: ~p"/images/#{@image}/tag_lock", class: "button" = if not @image.approved and can?(@conn, :approve, @image) do - = button_to "Approve image", Routes.image_approve_path(@conn, :create, @image), method: "post", class: "button button--state-success", data: [confirm: "Are you sure?"] + = button_to "Approve image", ~p"/images/#{@image}/approve", method: "post", class: "button button--state-success", data: [confirm: "Are you sure?"] = if @image.hidden_from_users and can?(@conn, :destroy, @image) do - = button_to "Destroy image", Routes.image_destroy_path(@conn, :create, @image), method: "post", class: "button button--state-danger", data: [confirm: "This action is IRREVERSIBLE. Are you sure?"] + = button_to "Destroy image", ~p"/images/#{@image}/destroy", method: "post", class: "button button--state-danger", data: [confirm: "This action is IRREVERSIBLE. Are you sure?"] diff --git a/lib/philomena_web/templates/image/_random_button.html.slime b/lib/philomena_web/templates/image/_random_button.html.slime index d383a3e3..c613c85c 100644 --- a/lib/philomena_web/templates/image/_random_button.html.slime +++ b/lib/philomena_web/templates/image/_random_button.html.slime @@ -1,3 +1,3 @@ -a href=Routes.image_random_path(@conn, :index, @params) title="Random Image" +a href=~p"/images/random?#{@params}" title="Random Image" i.fa.fa-random> span.hide-mobile.hide-limited-desktop Random Image diff --git a/lib/philomena_web/templates/image/_source.html.slime b/lib/philomena_web/templates/image/_source.html.slime index 2d39b306..8fa32872 100644 --- a/lib/philomena_web/templates/image/_source.html.slime +++ b/lib/philomena_web/templates/image/_source.html.slime @@ -1,6 +1,6 @@ .js-sourcesauce - has_sources = Enum.any?(@image.sources) - = form_for @changeset, Routes.image_source_path(@conn, :update, @image), [method: "put", class: "hidden", id: "source-form", data: [remote: "true"]], fn f -> + = form_for @changeset, ~p"/images/#{@image}/sources", [method: "put", class: "hidden", id: "source-form", data: [remote: "true"]], fn f -> = if can?(@conn, :edit_metadata, @image) and !@conn.assigns.current_ban do = if @changeset.action do .alert.alert-danger @@ -54,14 +54,14 @@ - else ' Add = if @source_change_count > 0 do - a.button.button--link.button--inline href=Routes.image_source_change_path(@conn, :index, @image) title="Source history" + a.button.button--link.button--inline href=~p"/images/#{@image}/source_changes" title="Source history" i.fa.fa-history> spanspan.hide-mobile> History | ( = @source_change_count | ) = if can?(@conn, :hide, @image) and not hide_staff_tools?(@conn) do - = form_for @changeset, Routes.image_source_history_path(@conn, :delete, @image), [method: "delete"], fn _f -> + = form_for @changeset, ~p"/images/#{@image}/source_history", [method: "delete"], fn _f -> a.button.button--state-danger.button--inline type="submit" data-confirm="Are you really, really sure?" title="Wipe sources" i.fas.fa-eraser> ' Wipe diff --git a/lib/philomena_web/templates/image/_tags.html.slime b/lib/philomena_web/templates/image/_tags.html.slime index 3c11c0c4..c4efb08a 100644 --- a/lib/philomena_web/templates/image/_tags.html.slime +++ b/lib/philomena_web/templates/image/_tags.html.slime @@ -12,7 +12,7 @@ ' The following tags have been restricted on this image: code= Enum.map_join(@image.locked_tags, ", ", & &1.name) - = form_for @changeset, Routes.image_tag_path(@conn, :update, @image), [id: "tags-form", method: "put", data: [remote: "true"]], fn f -> + = form_for @changeset, ~p"/images/#{@image}/tags", [id: "tags-form", method: "put", data: [remote: "true"]], fn f -> = if @changeset.action do .alert.alert-danger p Oops, something went wrong! Please check the errors below. @@ -66,7 +66,7 @@ i.fas.fa-edit> ' Edit = if @tag_change_count > 0 do - a.button.button--link.button--inline href=Routes.image_tag_change_path(@conn, :index, @image) title="Tag history" + a.button.button--link.button--inline href=~p"/images/#{@image}/tag_changes" title="Tag history" i.fa.fa-history> | History ( = @tag_change_count diff --git a/lib/philomena_web/templates/image/_uploader.html.slime b/lib/philomena_web/templates/image/_uploader.html.slime index 81d69284..504ab437 100644 --- a/lib/philomena_web/templates/image/_uploader.html.slime +++ b/lib/philomena_web/templates/image/_uploader.html.slime @@ -11,7 +11,7 @@ span.image_uploader i.fas.fa-eye = if can?(@conn, :show, :ip_address) do - = form_for @changeset, Routes.image_uploader_path(@conn, :update, @image), [class: "block__content hidden", id: "uploader-form", data: [remote: "true", method: "put"]], fn f -> + = form_for @changeset, ~p"/images/#{@image}/uploader", [class: "block__content hidden", id: "uploader-form", data: [remote: "true", method: "put"]], fn f -> => label f, :username, "Uploader" => text_input f, :username, value: username(@image.user), class: "input input--short input--small" @@ -21,6 +21,6 @@ span.image_uploader .image-anonymous.hidden = if @image.anonymous do - = button_to "Reveal author", Routes.image_anonymous_path(@conn, :delete, @image), class: "button button--small", method: "delete", data: [confirm: "Are you really, really sure?"] + = button_to "Reveal author", ~p"/images/#{@image}/anonymous", class: "button button--small", method: "delete", data: [confirm: "Are you really, really sure?"] - else - = button_to "Hide author", Routes.image_anonymous_path(@conn, :create, @image), class: "button button--small", method: "create", data: [confirm: "Are you really, really sure?"] + = button_to "Hide author", ~p"/images/#{@image}/anonymous", class: "button button--small", method: "create", data: [confirm: "Are you really, really sure?"] diff --git a/lib/philomena_web/templates/image/comment/_form.html.slime b/lib/philomena_web/templates/image/comment/_form.html.slime index 39b8a519..731ba817 100644 --- a/lib/philomena_web/templates/image/comment/_form.html.slime +++ b/lib/philomena_web/templates/image/comment/_form.html.slime @@ -1,6 +1,6 @@ - options = if(assigns[:remote], do: [data: [remote: "true"], id: "js-comment-form"], else: []) -= form_for @changeset, Routes.image_comment_path(@conn, :create, @image), options, fn f -> += form_for @changeset, ~p"/images/#{@image}/comments", options, fn f -> = if @changeset.action do .alert.alert-danger p Oops, something went wrong! Please check the errors below. diff --git a/lib/philomena_web/templates/image/comment/edit.html.slime b/lib/philomena_web/templates/image/comment/edit.html.slime index d7183a60..1b17c96a 100644 --- a/lib/philomena_web/templates/image/comment/edit.html.slime +++ b/lib/philomena_web/templates/image/comment/edit.html.slime @@ -1,4 +1,4 @@ -= form_for @changeset, Routes.image_comment_path(@conn, :update, @comment.image, @comment), fn f -> += form_for @changeset, ~p"/images/#{@comment.image}/comments/#{@comment}", fn f -> = if @changeset.action do .alert.alert-danger p Oops, something went wrong! Please check the errors below. diff --git a/lib/philomena_web/templates/image/comment/history/index.html.slime b/lib/philomena_web/templates/image/comment/history/index.html.slime index 3dd6e642..bb27e827 100644 --- a/lib/philomena_web/templates/image/comment/history/index.html.slime +++ b/lib/philomena_web/templates/image/comment/history/index.html.slime @@ -2,7 +2,7 @@ h1 ' Viewing last 25 versions of comment by = render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: @comment, conn: @conn ' on image - a href=Routes.image_path(@conn, :show, @comment.image) + a href=~p"/images/#{@comment.image}" | # = @comment.image_id diff --git a/lib/philomena_web/templates/image/comment/index.html.slime b/lib/philomena_web/templates/image/comment/index.html.slime index e0c3eee6..5e87cfe3 100644 --- a/lib/philomena_web/templates/image/comment/index.html.slime +++ b/lib/philomena_web/templates/image/comment/index.html.slime @@ -1,5 +1,5 @@ elixir: - route = fn p -> Routes.image_comment_path(@conn, :index, @image, p) end + route = fn p -> ~p"/images/#{@image}/comments?#{p}" end pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @comments, route: route .block diff --git a/lib/philomena_web/templates/image/deleted.html.slime b/lib/philomena_web/templates/image/deleted.html.slime index 4177b0a3..fc425b36 100644 --- a/lib/philomena_web/templates/image/deleted.html.slime +++ b/lib/philomena_web/templates/image/deleted.html.slime @@ -4,7 +4,7 @@ h1 This image has been merged into another image p ' This image was merged into image - => link "##{@image.duplicate_id}", to: Routes.image_path(@conn, :show, @image.duplicate_id) + => link "##{@image.duplicate_id}", to: ~p"/images/#{@image.duplicate_id}" ' because it was determined to be a duplicate of that image. - else diff --git a/lib/philomena_web/templates/image/description/_form.html.slime b/lib/philomena_web/templates/image/description/_form.html.slime index 6b4c4543..e47b5d3f 100644 --- a/lib/philomena_web/templates/image/description/_form.html.slime +++ b/lib/philomena_web/templates/image/description/_form.html.slime @@ -1,4 +1,4 @@ -= form_for @changeset, Routes.image_description_path(@conn, :update, @image), [class: "block hidden", id: "description-form", data: [remote: "true"]], fn f -> += form_for @changeset, ~p"/images/#{@image}/description", [class: "block hidden", id: "description-form", data: [remote: "true"]], fn f -> = if @changeset.action do .alert.alert-danger p Oops, something went wrong! Please check the errors below. diff --git a/lib/philomena_web/templates/image/favorite/index.html.slime b/lib/philomena_web/templates/image/favorite/index.html.slime index 1e606aad..ed239797 100644 --- a/lib/philomena_web/templates/image/favorite/index.html.slime +++ b/lib/philomena_web/templates/image/favorite/index.html.slime @@ -4,7 +4,7 @@ h5 = pluralize("user", "users", @image.faves_count) = for fave <- Enum.sort_by(@image.faves, & String.downcase(&1.user.name)) do - => link fave.user.name, to: Routes.profile_path(@conn, :show, fave.user), class: "interaction-user-list-item" + => link fave.user.name, to: ~p"/profiles/#{fave.user}", class: "interaction-user-list-item" = if @has_votes do h5 @@ -14,8 +14,8 @@ h5 = for upvote <- Enum.sort_by(@image.upvotes, & String.downcase(&1.user.name)) do span.interaction-user-list-item - => link upvote.user.name, to: Routes.profile_path(@conn, :show, upvote.user) - => link "(x)", to: Routes.image_tamper_path(@conn, :create, @image, user_id: upvote.user_id), method: "post" + => link upvote.user.name, to: ~p"/profiles/#{upvote.user}" + => link "(x)", to: ~p"/images/#{@image}/tamper?#{[user_id: upvote.user_id]}", method: "post" h5 ' Downvoted by @@ -24,8 +24,8 @@ h5 = for downvote <- Enum.sort_by(@image.downvotes, & String.downcase(&1.user.name)) do span.interaction-user-list-item - => link downvote.user.name, to: Routes.profile_path(@conn, :show, downvote.user) - => link "(x)", to: Routes.image_tamper_path(@conn, :create, @image, user_id: downvote.user_id), method: "post" + => link downvote.user.name, to: ~p"/profiles/#{downvote.user}" + => link "(x)", to: ~p"/images/#{@image}/tamper?#{[user_id: downvote.user_id]}", method: "post" h5 ' Hidden by @@ -33,4 +33,4 @@ h5 = pluralize("user", "users", @image.hides_count) = for hide <- Enum.sort_by(@image.hides, & String.downcase(&1.user.name)) do - => link hide.user.name, to: Routes.profile_path(@conn, :show, hide.user), class: "interaction-user-list-item" + => link hide.user.name, to: ~p"/profiles/#{hide.user}", class: "interaction-user-list-item" diff --git a/lib/philomena_web/templates/image/index.html.slime b/lib/philomena_web/templates/image/index.html.slime index a61acf49..ff5678cf 100644 --- a/lib/philomena_web/templates/image/index.html.slime +++ b/lib/philomena_web/templates/image/index.html.slime @@ -3,9 +3,9 @@ elixir: params = assigns[:params] || assigns[:scope] || [] scope = assigns[:scope] || [] tags = assigns[:tags] || [] - route = assigns[:route] || fn p -> Routes.image_path(@conn, :index, p) end - image_url = fn image -> Routes.image_path(@conn, :show, image, scope) end - sorted_url = fn image, hit -> Routes.image_path(@conn, :show, image, Keyword.put(scope, :sort, hit["sort"])) end + route = assigns[:route] || fn p -> ~p"/images?#{p}" end + image_url = fn image -> ~p"/images/#{image}?#{scope}" end + sorted_url = fn image, hit -> ~p"/images/#{image}?#{Keyword.put(scope, :sort, hit["sort"])}" end pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @images, route: route, params: params info = render PhilomenaWeb.PaginationView, "_pagination_info.html", page: @images diff --git a/lib/philomena_web/templates/image/new.html.slime b/lib/philomena_web/templates/image/new.html.slime index 0f2a98be..ad596f17 100644 --- a/lib/philomena_web/templates/image/new.html.slime +++ b/lib/philomena_web/templates/image/new.html.slime @@ -1,4 +1,4 @@ -= form_for @changeset, Routes.image_path(@conn, :create), [multipart: true], fn f -> += form_for @changeset, ~p"/images", [multipart: true], fn f -> .dnp-warning h4 ' Read the diff --git a/lib/philomena_web/templates/image/related/index.html.slime b/lib/philomena_web/templates/image/related/index.html.slime index 1feabfa1..421cee0a 100644 --- a/lib/philomena_web/templates/image/related/index.html.slime +++ b/lib/philomena_web/templates/image/related/index.html.slime @@ -8,4 +8,4 @@ .block__content.js-resizable-media-container = for image <- @images do - = render PhilomenaWeb.ImageView, "_image_box.html", image: image, link: Routes.image_path(@conn, :show, image), size: :thumb, conn: @conn + = render PhilomenaWeb.ImageView, "_image_box.html", image: image, link: ~p"/images/#{image}", size: :thumb, conn: @conn diff --git a/lib/philomena_web/templates/image/reporting/show.html.slime b/lib/philomena_web/templates/image/reporting/show.html.slime index 5a18b6c8..32216dbe 100644 --- a/lib/philomena_web/templates/image/reporting/show.html.slime +++ b/lib/philomena_web/templates/image/reporting/show.html.slime @@ -1,4 +1,4 @@ -a href=Routes.image_report_path(@conn, :new, @image) +a href=~p"/images/#{@image}/reports/new" button.button.button--link i.fa.fa-exclamation-triangle> ' General reporting @@ -15,7 +15,7 @@ a href=Routes.image_report_path(@conn, :new, @image) - else p ' You must - a> href=Routes.session_path(@conn, :new) log in + a> href=~p"/sessions/new" log in ' to report duplicate images. - target_reports = Enum.filter(@dupe_reports, & &1.duplicate_of_image_id == @image.id) diff --git a/lib/philomena_web/templates/image/scratchpad/edit.html.slime b/lib/philomena_web/templates/image/scratchpad/edit.html.slime index 31e37f9f..bd27ab6e 100644 --- a/lib/philomena_web/templates/image/scratchpad/edit.html.slime +++ b/lib/philomena_web/templates/image/scratchpad/edit.html.slime @@ -1,8 +1,8 @@ h1 ' Editing moderation notes for image - = link "##{@image.id}", to: Routes.image_path(@conn, :show, @image) + = link "##{@image.id}", to: ~p"/images/#{@image}" -= form_for @changeset, Routes.image_scratchpad_path(@conn, :update, @image), fn f -> += form_for @changeset, ~p"/images/#{@image}/scratchpad", fn f -> .field = textarea f, :scratchpad, placeholder: "Scratchpad contents", class: "input input--wide" diff --git a/lib/philomena_web/templates/image/show.html.slime b/lib/philomena_web/templates/image/show.html.slime index 0c566314..2c2a8f23 100644 --- a/lib/philomena_web/templates/image/show.html.slime +++ b/lib/philomena_web/templates/image/show.html.slime @@ -24,5 +24,5 @@ - true -> - #comments data-current-url=Routes.image_comment_path(@conn, :index, @image) data-loaded="true" + #comments data-current-url=~p"/images/#{@image}/comments" data-loaded="true" = render PhilomenaWeb.Image.CommentView, "index.html", image: @image, comments: @comments, conn: @conn diff --git a/lib/philomena_web/templates/image/source_change/index.html.slime b/lib/philomena_web/templates/image/source_change/index.html.slime index 712f434a..bd5f4a57 100644 --- a/lib/philomena_web/templates/image/source_change/index.html.slime +++ b/lib/philomena_web/templates/image/source_change/index.html.slime @@ -1,10 +1,10 @@ h1 ' Source changes for - a href=Routes.image_path(@conn, :show, @image) + a href=~p"/images/#{@image}" | image # = @image.id -- route = fn p -> Routes.image_source_change_path(@conn, :index, @image, p) end +- route = fn p -> ~p"/images/#{@image}/source_changes?#{p}" end - pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @source_changes, route: route, conn: @conn = render PhilomenaWeb.SourceChangeView, "index.html", conn: @conn, source_changes: @source_changes, pagination: pagination \ No newline at end of file diff --git a/lib/philomena_web/templates/image/subscription/_subscription.html.slime b/lib/philomena_web/templates/image/subscription/_subscription.html.slime index 35c6883d..323fc0d5 100644 --- a/lib/philomena_web/templates/image/subscription/_subscription.html.slime +++ b/lib/philomena_web/templates/image/subscription/_subscription.html.slime @@ -1,8 +1,8 @@ elixir: - watch_path = Routes.image_subscription_path(@conn, :create, @image) + watch_path = ~p"/images/#{@image}/subscription" watch_class = if @watching, do: "hidden", else: "" - unwatch_path = Routes.image_subscription_path(@conn, :delete, @image) + unwatch_path = ~p"/images/#{@image}/subscription" unwatch_class = if @watching, do: "", else: "hidden" = if @conn.assigns.current_user do @@ -15,6 +15,6 @@ elixir: i.fa.fa-bell-slash> ' Unsubscribe - else - a href=Routes.session_path(@conn, :new) + a href=~p"/sessions/new" i.fa.fa-bell> ' Subscribe diff --git a/lib/philomena_web/templates/image/tag_change/index.html.slime b/lib/philomena_web/templates/image/tag_change/index.html.slime index 82d78789..cd79ec97 100644 --- a/lib/philomena_web/templates/image/tag_change/index.html.slime +++ b/lib/philomena_web/templates/image/tag_change/index.html.slime @@ -1,10 +1,10 @@ h1 ' Tag changes for - a href=Routes.image_path(@conn, :show, @image) + a href=~p"/images/#{@image}" | image # = @image.id -- route = fn p -> Routes.image_tag_change_path(@conn, :index, @image, p) end +- route = fn p -> ~p"/images/#{@image}/tag_changes?#{p}" end - params = if @conn.params["added"], do: [added: @conn.params["added"]] - pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @tag_changes, route: route, conn: @conn, params: params @@ -13,8 +13,8 @@ h1 span.block__header__title | Display only: - = link "Removed", to: Routes.image_tag_change_path(@conn, :index, @image, added: 0) - = link "Added", to: Routes.image_tag_change_path(@conn, :index, @image, added: 1) - = link "All", to: Routes.image_tag_change_path(@conn, :index, @image) + = link "Removed", to: ~p"/images/#{@image}/tag_changes?#{[added: 0]}" + = link "Added", to: ~p"/images/#{@image}/tag_changes?#{[added: 1]}" + = link "All", to: ~p"/images/#{@image}/tag_changes" = render PhilomenaWeb.TagChangeView, "index.html", conn: @conn, tag_changes: @tag_changes, pagination: pagination diff --git a/lib/philomena_web/templates/image/tag_lock/show.html.slime b/lib/philomena_web/templates/image/tag_lock/show.html.slime index 81a52cdf..e5a9841d 100644 --- a/lib/philomena_web/templates/image/tag_lock/show.html.slime +++ b/lib/philomena_web/templates/image/tag_lock/show.html.slime @@ -4,7 +4,7 @@ h1 | Editing locked tags on image # = @image.id -= form_for @changeset, Routes.image_tag_lock_path(@conn, :update, @image), fn f -> += form_for @changeset, ~p"/images/#{@image}/tag_lock", fn f -> .field = render PhilomenaWeb.TagView, "_tag_editor.html", f: f, name: :tag_input, type: :edit, extra: [value: tag_input] = error_tag f, :tag_input diff --git a/lib/philomena_web/templates/ip_profile/show.html.slime b/lib/philomena_web/templates/ip_profile/show.html.slime index c752d9ff..eb3ac25c 100644 --- a/lib/philomena_web/templates/ip_profile/show.html.slime +++ b/lib/philomena_web/templates/ip_profile/show.html.slime @@ -3,24 +3,24 @@ h1 ' 's IP profile ul - li = link "View images this IP has uploaded", to: Routes.search_path(@conn, :index, q: "ip:#{@ip}") - li = link "View comments this IP has posted", to: Routes.comment_path(@conn, :index, cq: "ip:#{@ip}") - li = link "View posts this IP has made", to: Routes.post_path(@conn, :index, pq: "ip:#{@ip}") + li = link "View images this IP has uploaded", to: ~p"/search?#{[q: "ip:#{@ip}"]}" + li = link "View comments this IP has posted", to: ~p"/comments?#{[cq: "ip:#{@ip}"]}" + li = link "View posts this IP has made", to: ~p"/posts?#{[pq: "ip:#{@ip}"]}" = render PhilomenaWeb.BanView, "_bans.html", bans: @subnet_bans, conn: @conn h2 Administration Options ul - li = link "View tag changes", to: Routes.ip_profile_tag_change_path(@conn, :index, to_string(@ip)) - li = link "View source URL history", to: Routes.ip_profile_source_change_path(@conn, :index, to_string(@ip)) - li = link "View reports this IP has made", to: Routes.admin_report_path(@conn, :index, rq: "ip:#{@ip}") - li = link "View IP ban history", to: Routes.admin_subnet_ban_path(@conn, :index, ip: to_string(@ip)) - li = link "Ban this sucker", to: Routes.admin_subnet_ban_path(@conn, :new, specification: to_string(@ip)) + li = link "View tag changes", to: ~p"/ip_profiles/#{to_string(@ip)}/tag_changes" + li = link "View source URL history", to: ~p"/ip_profiles/#{to_string(@ip)}/source_changes" + li = link "View reports this IP has made", to: ~p"/admin/reports?#{[rq: "ip:#{@ip}"]}" + li = link "View IP ban history", to: ~p"/admin/subnet_bans?#{[ip: to_string(@ip)]}" + li = link "Ban this sucker", to: ~p"/admin/subnet_bans/new?#{[specification: to_string(@ip)]}" h2 Actions ul - li = link "Revert all tag changes", to: Routes.tag_change_full_revert_path(@conn, :create, [ip: to_string(@ip)]), data: [confirm: "Are you really, really sure?", method: "create"] - li = link "...the button above didn't work (use carefully, this is resource-intensive)", to: Routes.tag_change_full_revert_path(@conn, :create, [ip: to_string(@ip), batch_size: 1]), data: [confirm: "Please confirm that you're aware that this may crash the site and are ready to take on the full wrath of the admins if it does so after you press this button.", method: "create"] + li = link "Revert all tag changes", to: ~p"/tag_changes/full_revert?#{[ip: to_string(@ip)]}", data: [confirm: "Are you really, really sure?", method: "create"] + li = link "...the button above didn't work (use carefully, this is resource-intensive)", to: ~p"/tag_changes/full_revert?#{[ip: to_string(@ip), batch_size: 1]}", data: [confirm: "Please confirm that you're aware that this may crash the site and are ready to take on the full wrath of the admins if it does so after you press this button.", method: "create"] h4 Observed users table.table @@ -34,7 +34,7 @@ table.table = for uip <- @user_ips do tr td - = link uip.user.name, to: Routes.profile_path(@conn, :show, uip.user) + = link uip.user.name, to: ~p"/profiles/#{uip.user}" td => uip.uses ' times diff --git a/lib/philomena_web/templates/ip_profile/source_change/index.html.slime b/lib/philomena_web/templates/ip_profile/source_change/index.html.slime index 5bf1bea1..d31a7968 100644 --- a/lib/philomena_web/templates/ip_profile/source_change/index.html.slime +++ b/lib/philomena_web/templates/ip_profile/source_change/index.html.slime @@ -2,7 +2,7 @@ h1 ' Source changes by = @ip -- route = fn p -> Routes.ip_profile_source_change_path(@conn, :index, to_string(@ip), p) end +- route = fn p -> ~p"/ip_profiles/#{to_string(@ip)}/source_changes?#{p}" end - pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @source_changes, route: route, conn: @conn = render PhilomenaWeb.SourceChangeView, "index.html", conn: @conn, source_changes: @source_changes, pagination: pagination diff --git a/lib/philomena_web/templates/ip_profile/tag_change/index.html.slime b/lib/philomena_web/templates/ip_profile/tag_change/index.html.slime index 7d86ae72..4eb2f114 100644 --- a/lib/philomena_web/templates/ip_profile/tag_change/index.html.slime +++ b/lib/philomena_web/templates/ip_profile/tag_change/index.html.slime @@ -2,7 +2,7 @@ h1 ' Tag changes by = @ip -- route = fn p -> Routes.ip_profile_tag_change_path(@conn, :index, to_string(@ip), p) end +- route = fn p -> ~p"/ip_profiles/#{to_string(@ip)}/tag_changes?#{p}" end - params = if @conn.params["added"], do: [added: @conn.params["added"]] - pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @tag_changes, route: route, conn: @conn, params: params @@ -11,8 +11,8 @@ h1 span.block__header__title | Display only: - = link "Removed", to: Routes.ip_profile_tag_change_path(@conn, :index, to_string(@ip), added: 0) - = link "Added", to: Routes.ip_profile_tag_change_path(@conn, :index, to_string(@ip), added: 1) - = link "All", to: Routes.ip_profile_tag_change_path(@conn, :index, to_string(@ip)) + = link "Removed", to: ~p"/ip_profiles/#{to_string(@ip)}/tag_changes?#{[added: 0]}" + = link "Added", to: ~p"/ip_profiles/#{to_string(@ip)}/tag_changes?#{[added: 1]}" + = link "All", to: ~p"/ip_profiles/#{to_string(@ip)}/tag_changes" = render PhilomenaWeb.TagChangeView, "index.html", conn: @conn, tag_changes: @tag_changes, pagination: pagination diff --git a/lib/philomena_web/templates/layout/_header.html.slime b/lib/philomena_web/templates/layout/_header.html.slime index 23935c9c..27a837c4 100644 --- a/lib/philomena_web/templates/layout/_header.html.slime +++ b/lib/philomena_web/templates/layout/_header.html.slime @@ -11,7 +11,7 @@ header.header a.header__link.hide-mobile href="/images/new" title="Upload" i.fa.fa-upload - = form_for @conn, Routes.search_path(@conn, :index), [method: "get", class: "header__search flex flex--no-wrap flex--centered", enforce_utf8: false], fn f -> + = form_for @conn, ~p"/search", [method: "get", class: "header__search flex flex--no-wrap flex--centered", enforce_utf8: false], fn f -> input.input.header__input.header__input--search#q name="q" title="For terms all required, separate with ',' or 'AND'; also supports 'OR' for optional terms and '-' or 'NOT' for negation. Search with a blank query for more options or click the ? for syntax help." value=@conn.params["q"] placeholder="Search" autocapitalize="none" = if present?(@conn.params["sf"]) do @@ -51,18 +51,18 @@ header.header i.fa.fa-filter span.hide-limited-desktop< Filters - = form_for @user_changeset, Routes.filter_current_path(@conn, :update), [class: "header__filter-form", id: "filter-quick-form"], fn f -> + = form_for @user_changeset, ~p"/filters/current", [class: "header__filter-form", id: "filter-quick-form"], fn f -> = select f, :current_filter_id, @available_filters, name: "id", id: "filter-quick-menu", class: "input header__input", data: [change_submit: "#filter-quick-form"], autocomplete: "off" - = form_for @user_changeset, Routes.filter_spoiler_type_path(@conn, :update), [class: "header__filter-form hide-mobile hide-limited-desktop", id: "spoiler-quick-form"], fn f -> + = form_for @user_changeset, ~p"/filters/spoiler_type", [class: "header__filter-form hide-mobile hide-limited-desktop", id: "spoiler-quick-form"], fn f -> = select f, :spoiler_type, @spoiler_types, id: "spoiler-quick-menu", class: "input header__input", data: [change_submit: "#spoiler-quick-form"], autocomplete: "off" .dropdown.header__dropdown - a.header__link.header__link-user href=Routes.profile_path(@conn, :show, @current_user) + a.header__link.header__link-user href=~p"/profiles/#{@current_user}" = render PhilomenaWeb.UserAttributionView, "_user_avatar.html", object: %{user: @current_user}, class: "avatar--28px" span.header__link-user__dropdown-arrow.hide-mobile data-click-preventdefault="true" nav.dropdown__content.dropdown__content-right.hide-mobile.js-burger-links - a.header__link href=Routes.profile_path(@conn, :show, @current_user) + a.header__link href=~p"/profiles/#{@current_user}" = @current_user.name a.header__link href="/search?q=my:watched" i.fa.fa-fw.fa-eye> @@ -73,7 +73,7 @@ header.header a.header__link href="/search?q=my:upvotes" i.fa.fa-fw.fa-arrow-up> | Upvotes - a.header__link href=Routes.gallery_path(@conn, :index, gallery: [creator: @current_user.name]) + a.header__link href=~p"/galleries?#{[gallery: [creator: @current_user.name]]}" i.fa.fa-fw.fa-image> | Galleries a.header__link href="/search?q=my:uploads" @@ -85,7 +85,7 @@ header.header a.header__link href="/posts?pq=my:posts" i.fas.fa-fw.fa-pen-square> | Posts - a.header__link href=Routes.profile_artist_link_path(@conn, :index, @current_user) + a.header__link href=~p"/profiles/#{@current_user}/artist_links" i.fa.fa-fw.fa-link> | Links a.header__link href="/settings/edit" @@ -94,10 +94,10 @@ header.header a.header__link href="/conversations" i.fa.fa-fw.fa-envelope> | Messages - a.header__link href=Routes.registration_path(@conn, :edit) + a.header__link href=~p"/registrations/edit" i.fa.fa-fw.fa-user> | Account - a.header__link href=Routes.session_path(@conn, :delete) data-method="delete" + a.header__link href=~p"/sessions" data-method="delete" i.fa.fa-fw.fa-sign-out-alt> | Logout - else @@ -109,9 +109,9 @@ header.header a.header__link href="/settings/edit" i.fa.fa-fw.fa-cogs.hide-desktop> | Settings - a.header__link href=Routes.registration_path(@conn, :new) + a.header__link href=~p"/registrations/new" | Register - a.header__link href=Routes.session_path(@conn, :new) + a.header__link href=~p"/sessions/new" | Login nav.header.header--secondary diff --git a/lib/philomena_web/templates/layout/_header_navigation.html.slime b/lib/philomena_web/templates/layout/_header_navigation.html.slime index 112b0c57..af53a163 100644 --- a/lib/philomena_web/templates/layout/_header_navigation.html.slime +++ b/lib/philomena_web/templates/layout/_header_navigation.html.slime @@ -22,7 +22,7 @@ i.fa.fa-caret-down< .dropdown__content = for forum <- @conn.assigns.forums do - a.header__link href=Routes.forum_path(@conn, :show, forum) + a.header__link href=~p"/forums/#{forum}" = forum.name a.header__link href="/posts" diff --git a/lib/philomena_web/templates/layout/_header_staff_links.html.slime b/lib/philomena_web/templates/layout/_header_staff_links.html.slime index 52d6aef6..59c6126b 100644 --- a/lib/philomena_web/templates/layout/_header_staff_links.html.slime +++ b/lib/philomena_web/templates/layout/_header_staff_links.html.slime @@ -7,71 +7,71 @@ .dropdown__content.js-burger-links = if manages_site_notices?(@conn) do - = link to: Routes.admin_site_notice_path(@conn, :index), class: "header__link" do + = link to: ~p"/admin/site_notices", class: "header__link" do i.fa.fa-fw.fa-info-circle> ' Site Notices = if manages_users?(@conn) do - = link to: Routes.admin_user_path(@conn, :index), class: "header__link" do + = link to: ~p"/admin/users", class: "header__link" do i.fa.fa-fw.fa-users> ' Users = if manages_forums?(@conn) do - = link to: Routes.admin_forum_path(@conn, :index), class: "header__link" do + = link to: ~p"/admin/forums", class: "header__link" do i.fa.fa-fw.fa-paragraph> ' Forums = if manages_ads?(@conn) do - = link to: Routes.admin_advert_path(@conn, :index), class: "header__link" do + = link to: ~p"/admin/adverts", class: "header__link" do i.fa.fa-fw.fa-shopping-bag> ' Adverts = if manages_badges?(@conn) do - = link to: Routes.admin_badge_path(@conn, :index), class: "header__link" do + = link to: ~p"/admin/badges", class: "header__link" do i.fa.fa-fw.fa-trophy> ' Badges = if manages_static_pages?(@conn) do - = link to: Routes.page_path(@conn, :index), class: "header__link" do + = link to: ~p"/pages", class: "header__link" do i.fa.fa-fw.fa-sticky-note> ' Pages = if manages_mod_notes?(@conn) do - = link to: Routes.admin_mod_note_path(@conn, :index), class: "header__link" do + = link to: ~p"/admin/mod_notes", class: "header__link" do i.fa.fa-fw.fa-clipboard> ' Mod Notes = if can_see_moderation_log?(@conn) do - = link to: Routes.moderation_log_path(@conn, :index), class: "header__link" do + = link to: ~p"/moderation_logs", class: "header__link" do i.fa.fa-fw.fa-list-alt> ' Mod Logs = if @pending_approval_count do - = link to: Routes.admin_approval_path(@conn, :index), class: "header__link", title: "Approval Queue" do + = link to: ~p"/admin/approvals", class: "header__link", title: "Approval Queue" do ' Q span.header__counter__admin = @pending_approval_count = if @duplicate_report_count do - = link to: Routes.duplicate_report_path(@conn, :index), class: "header__link", title: "Duplicates" do + = link to: ~p"/duplicate_reports", class: "header__link", title: "Duplicates" do ' D span.header__counter__admin = @duplicate_report_count = if @report_count do - = link to: Routes.admin_report_path(@conn, :index), class: "header__link", title: "Reports" do + = link to: ~p"/admin/reports", class: "header__link", title: "Reports" do ' R span.header__counter__admin = @report_count = if @artist_link_count do - = link to: Routes.admin_artist_link_path(@conn, :index), class: "header__link", title: "Artist Links" do + = link to: ~p"/admin/artist_links", class: "header__link", title: "Artist Links" do ' L span.header__counter__admin = @artist_link_count = if @dnp_entry_count do - = link to: Routes.admin_dnp_entry_path(@conn, :index), class: "header__link", title: "DNP Requests" do + = link to: ~p"/admin/dnp_entries", class: "header__link", title: "DNP Requests" do ' S span.header__counter__admin = @dnp_entry_count @@ -84,14 +84,14 @@ .dropdown__content.dropdown__content-right.js-burger-links - = link to: Routes.admin_user_ban_path(@conn, :index), class: "header__link" do + = link to: ~p"/admin/user_bans", class: "header__link" do i.fa.fa-fw.fa-user> ' User Bans - = link to: Routes.admin_subnet_ban_path(@conn, :index), class: "header__link" do + = link to: ~p"/admin/subnet_bans", class: "header__link" do i.fab.fa-fw.fa-internet-explorer> ' IP Bans - = link to: Routes.admin_fingerprint_ban_path(@conn, :index), class: "header__link" do + = link to: ~p"/admin/fingerprint_bans", class: "header__link" do i.fa.fa-fw.fa-desktop> ' FP Bans diff --git a/lib/philomena_web/templates/layout/_opengraph.html.slime b/lib/philomena_web/templates/layout/_opengraph.html.slime index 30ae6555..45585171 100644 --- a/lib/philomena_web/templates/layout/_opengraph.html.slime +++ b/lib/philomena_web/templates/layout/_opengraph.html.slime @@ -12,7 +12,7 @@ meta name="format-detection" content="telephone=no" meta name="keywords" content=tag_list(image) meta name="description" content=description meta property="og:title" content=description - meta property="og:url" content=Routes.image_url(@conn, :show, image) + meta property="og:url" content=url(~p"/images/#{image}") = for tag <- artist_tags(image.tags) do meta property="dc:creator" content=tag.name_in_namespace @@ -20,9 +20,9 @@ meta name="format-detection" content="telephone=no" = if image_has_sources(image) do meta property="foaf:primaryTopic" content=image_first_source(image) - link rel="alternate" type="application/json+oembed" href=Routes.api_json_oembed_url(@conn, :index, url: Routes.image_path(@conn, :show, image)) title="oEmbed JSON Profile" + link rel="alternate" type="application/json+oembed" href=url(~p"/api/v1/json/oembed?#{[url: ~p"/images/#{image}"]}") title="oEmbed JSON Profile" - link rel="canonical" href=Routes.image_url(@conn, :show, image) + link rel="canonical" href=url(~p"/images/#{image}") = cond do - image.image_mime_type == "video/webm" and not filtered -> diff --git a/lib/philomena_web/templates/message/_message.html.slime b/lib/philomena_web/templates/message/_message.html.slime index 27f4bd96..9f750121 100644 --- a/lib/philomena_web/templates/message/_message.html.slime +++ b/lib/philomena_web/templates/message/_message.html.slime @@ -9,7 +9,7 @@ article.block.communication p ul.horizontal-list li - = link(to: Routes.conversation_message_approve_path(@conn, :create, @message.conversation_id, @message), data: [confirm: "Are you sure?"], method: "post", class: "button") do + = link(to: ~p"/conversations/#{@message.conversation_id}/messages/#{@message}/approve", data: [confirm: "Are you sure?"], method: "post", class: "button") do i.fas.fa-check> ' Approve diff --git a/lib/philomena_web/templates/moderation_log/index.html.slime b/lib/philomena_web/templates/moderation_log/index.html.slime index a1927305..e2c81eef 100644 --- a/lib/philomena_web/templates/moderation_log/index.html.slime +++ b/lib/philomena_web/templates/moderation_log/index.html.slime @@ -1,5 +1,5 @@ elixir: - route = fn p -> Routes.moderation_log_path(@conn, :index, p) end + route = fn p -> ~p"/moderation_logs?#{p}" end pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @moderation_logs, route: route, conn: @conn h1 Listing Moderation Logs diff --git a/lib/philomena_web/templates/notification/_channel.html.slime b/lib/philomena_web/templates/notification/_channel.html.slime index 3e40d6f3..1fc57157 100644 --- a/lib/philomena_web/templates/notification/_channel.html.slime +++ b/lib/philomena_web/templates/notification/_channel.html.slime @@ -1,14 +1,14 @@ .flex.flex--centered.flex__grow div strong> - = link @notification.actor.title, to: Routes.channel_path(@conn, :show, @notification.actor) + = link @notification.actor.title, to: ~p"/channels/#{@notification.actor}" =<> @notification.action => pretty_time @notification.updated_at .flex.flex--centered.flex--no-wrap - a.button.button--separate-right title="Delete" href=Routes.channel_read_path(@conn, :create, @notification.actor) data-method="post" data-remote="true" data-fetchcomplete-hide="#notification-#{@notification.id}" + a.button.button--separate-right title="Delete" href=~p"/channels/#{@notification.actor}/read" data-method="post" data-remote="true" data-fetchcomplete-hide="#notification-#{@notification.id}" i.fa.fa-trash - a.button title="Unsubscribe" href=Routes.channel_subscription_path(@conn, :delete, @notification.actor) data-method="delete" data-remote="true" data-fetchcomplete-hide="#notification-#{@notification.id}" + a.button title="Unsubscribe" href=~p"/channels/#{@notification.actor}/subscription" data-method="delete" data-remote="true" data-fetchcomplete-hide="#notification-#{@notification.id}" i.fa.fa-bell-slash \ No newline at end of file diff --git a/lib/philomena_web/templates/notification/_forum.html.slime b/lib/philomena_web/templates/notification/_forum.html.slime index 512c49ea..f7edb198 100644 --- a/lib/philomena_web/templates/notification/_forum.html.slime +++ b/lib/philomena_web/templates/notification/_forum.html.slime @@ -9,17 +9,17 @@ ' titled strong> - = link topic.title, to: Routes.forum_topic_path(@conn, :show, forum, topic) + = link topic.title, to: ~p"/forums/#{forum}/topics/#{topic}" ' in - => link forum.name, to: Routes.forum_path(@conn, :show, forum) + => link forum.name, to: ~p"/forums/#{forum}" => pretty_time @notification.updated_at .flex.flex--centered.flex--no-wrap - a.button.button--separate-right title="Delete" href=Routes.forum_read_path(@conn, :create, forum) data-method="post" data-remote="true" data-fetchcomplete-hide="#notification-#{@notification.id}" + a.button.button--separate-right title="Delete" href=~p"/forums/#{forum}/read" data-method="post" data-remote="true" data-fetchcomplete-hide="#notification-#{@notification.id}" i.fa.fa-trash - a.button title="Unsubscribe" href=Routes.forum_subscription_path(@conn, :delete, forum) data-method="delete" data-remote="true" data-fetchcomplete-hide="#notification-#{@notification.id}" + a.button title="Unsubscribe" href=~p"/forums/#{forum}/subscription" data-method="delete" data-remote="true" data-fetchcomplete-hide="#notification-#{@notification.id}" i.fa.fa-bell-slash \ No newline at end of file diff --git a/lib/philomena_web/templates/notification/_gallery.html.slime b/lib/philomena_web/templates/notification/_gallery.html.slime index 767cbc73..09e3eccc 100644 --- a/lib/philomena_web/templates/notification/_gallery.html.slime +++ b/lib/philomena_web/templates/notification/_gallery.html.slime @@ -4,13 +4,13 @@ => @notification.action strong> - = link @notification.actor.title, to: Routes.gallery_path(@conn, :show, @notification.actor) + = link @notification.actor.title, to: ~p"/galleries/#{@notification.actor}" => pretty_time @notification.updated_at .flex.flex--centered.flex--no-wrap - a.button.button--separate-right title="Delete" href=Routes.gallery_read_path(@conn, :create, @notification.actor) data-method="post" data-remote="true" data-fetchcomplete-hide="#notification-#{@notification.id}" + a.button.button--separate-right title="Delete" href=~p"/galleries/#{@notification.actor}/read" data-method="post" data-remote="true" data-fetchcomplete-hide="#notification-#{@notification.id}" i.fa.fa-trash - a.button title="Unsubscribe" href=Routes.gallery_subscription_path(@conn, :delete, @notification.actor) data-method="delete" data-remote="true" data-fetchcomplete-hide="#notification-#{@notification.id}" + a.button title="Unsubscribe" href=~p"/galleries/#{@notification.actor}/subscription" data-method="delete" data-remote="true" data-fetchcomplete-hide="#notification-#{@notification.id}" i.fa.fa-bell-slash \ No newline at end of file diff --git a/lib/philomena_web/templates/notification/_image.html.slime b/lib/philomena_web/templates/notification/_image.html.slime index ebedb422..89814c39 100644 --- a/lib/philomena_web/templates/notification/_image.html.slime +++ b/lib/philomena_web/templates/notification/_image.html.slime @@ -7,13 +7,13 @@ => @notification.action strong> - = link "##{@notification.actor_id}", to: Routes.image_path(@conn, :show, @notification.actor) <> "#comments" + = link "##{@notification.actor_id}", to: ~p"/images/#{@notification.actor}" <> "#comments" => pretty_time @notification.updated_at .flex.flex--centered.flex--no-wrap - a.button.button--separate-right title="Delete" href=Routes.image_read_path(@conn, :create, @notification.actor) data-method="post" data-remote="true" data-fetchcomplete-hide="#notification-#{@notification.id}" + a.button.button--separate-right title="Delete" href=~p"/images/#{@notification.actor}/read" data-method="post" data-remote="true" data-fetchcomplete-hide="#notification-#{@notification.id}" i.fa.fa-trash - a.button title="Unsubscribe" href=Routes.image_subscription_path(@conn, :delete, @notification.actor) data-method="delete" data-remote="true" data-fetchcomplete-hide="#notification-#{@notification.id}" + a.button title="Unsubscribe" href=~p"/images/#{@notification.actor}/subscription" data-method="delete" data-remote="true" data-fetchcomplete-hide="#notification-#{@notification.id}" i.fa.fa-bell-slash \ No newline at end of file diff --git a/lib/philomena_web/templates/notification/_topic.html.slime b/lib/philomena_web/templates/notification/_topic.html.slime index 1a1c5ff6..5ecefcfd 100644 --- a/lib/philomena_web/templates/notification/_topic.html.slime +++ b/lib/philomena_web/templates/notification/_topic.html.slime @@ -7,13 +7,13 @@ => @notification.action strong> - = link topic.title, to: Routes.forum_topic_path(@conn, :show, topic.forum, topic, post_id: post.id) <> "#post_#{post.id}" + = link topic.title, to: ~p"/forums/#{topic.forum}/topics/#{topic}?#{[post_id: post.id]}" <> "#post_#{post.id}" => pretty_time @notification.updated_at .flex.flex--centered.flex--no-wrap - a.button.button--separate-right title="Delete" href=Routes.forum_topic_read_path(@conn, :create, topic.forum, topic) data-method="post" data-remote="true" data-fetchcomplete-hide="#notification-#{@notification.id}" + a.button.button--separate-right title="Delete" href=~p"/forums/#{topic.forum}/topics/#{topic}/read" data-method="post" data-remote="true" data-fetchcomplete-hide="#notification-#{@notification.id}" i.fa.fa-trash - a.button title="Unsubscribe" href=Routes.forum_topic_subscription_path(@conn, :delete, topic.forum, topic) data-method="delete" data-remote="true" data-fetchcomplete-hide="#notification-#{@notification.id}" + a.button title="Unsubscribe" href=~p"/forums/#{topic.forum}/topics/#{topic}/subscription" data-method="delete" data-remote="true" data-fetchcomplete-hide="#notification-#{@notification.id}" i.fa.fa-bell-slash \ No newline at end of file diff --git a/lib/philomena_web/templates/notification/index.html.slime b/lib/philomena_web/templates/notification/index.html.slime index 5478763b..9cec1086 100644 --- a/lib/philomena_web/templates/notification/index.html.slime +++ b/lib/philomena_web/templates/notification/index.html.slime @@ -1,4 +1,4 @@ -- route = fn p -> Routes.notification_path(@conn, :index, p) end +- route = fn p -> ~p"/notifications?#{p}" end h1 Notification Area .walloftext diff --git a/lib/philomena_web/templates/page/edit.html.slime b/lib/philomena_web/templates/page/edit.html.slime index 2ac4387b..f141d06b 100644 --- a/lib/philomena_web/templates/page/edit.html.slime +++ b/lib/philomena_web/templates/page/edit.html.slime @@ -1,3 +1,3 @@ h1 Editing static page -= render PhilomenaWeb.PageView, "_form.html", changeset: @changeset, action: Routes.page_path(@conn, :update, @static_page), conn: @conn += render PhilomenaWeb.PageView, "_form.html", changeset: @changeset, action: ~p"/pages/#{@static_page}", conn: @conn diff --git a/lib/philomena_web/templates/page/history/index.html.slime b/lib/philomena_web/templates/page/history/index.html.slime index cc7429f7..805492eb 100644 --- a/lib/philomena_web/templates/page/history/index.html.slime +++ b/lib/philomena_web/templates/page/history/index.html.slime @@ -1,6 +1,6 @@ h1 ' Revision history for - = link @static_page.title, to: Routes.page_path(@conn, :show, @static_page) + = link @static_page.title, to: ~p"/pages/#{@static_page}" table.table thead @@ -12,7 +12,7 @@ table.table tbody = for version <- @versions do tr - td = link version.user.name, to: Routes.profile_path(@conn, :show, version.user) + td = link version.user.name, to: ~p"/profiles/#{version.user}" td = pretty_time(version.created_at) td.static-page__diff = for diff <- version.difference do diff --git a/lib/philomena_web/templates/page/index.html.slime b/lib/philomena_web/templates/page/index.html.slime index 88731d64..5e535faa 100644 --- a/lib/philomena_web/templates/page/index.html.slime +++ b/lib/philomena_web/templates/page/index.html.slime @@ -8,7 +8,7 @@ table.table tbody = for static_page <- @static_pages do tr - td = link static_page.title, to: Routes.page_path(@conn, :show, static_page) + td = link static_page.title, to: ~p"/pages/#{static_page}" br -= link "New static page", to: Routes.page_path(@conn, :new) += link "New static page", to: ~p"/pages/new" diff --git a/lib/philomena_web/templates/page/new.html.slime b/lib/philomena_web/templates/page/new.html.slime index 48ad0fd1..c2b7b208 100644 --- a/lib/philomena_web/templates/page/new.html.slime +++ b/lib/philomena_web/templates/page/new.html.slime @@ -1,3 +1,3 @@ h1 New static page -= render PhilomenaWeb.PageView, "_form.html", changeset: @changeset, action: Routes.page_path(@conn, :create), conn: @conn += render PhilomenaWeb.PageView, "_form.html", changeset: @changeset, action: ~p"/pages", conn: @conn diff --git a/lib/philomena_web/templates/page/show.html.slime b/lib/philomena_web/templates/page/show.html.slime index 9eadee5f..f5bc82cc 100644 --- a/lib/philomena_web/templates/page/show.html.slime +++ b/lib/philomena_web/templates/page/show.html.slime @@ -4,11 +4,11 @@ p => pretty_time(@static_page.updated_at) p - => link to: Routes.page_history_path(@conn, :index, @static_page) do + => link to: ~p"/pages/#{@static_page}/history" do i.fa.fa-history> ' Revision history = if can?(@conn, :edit, Philomena.StaticPages.StaticPage) do - =< link to: Routes.page_path(@conn, :edit, @static_page) do + =< link to: ~p"/pages/#{@static_page}/edit" do i.fa.fa-edit> ' Edit diff --git a/lib/philomena_web/templates/password/edit.html.slime b/lib/philomena_web/templates/password/edit.html.slime index 0046b4d9..00cf1f71 100644 --- a/lib/philomena_web/templates/password/edit.html.slime +++ b/lib/philomena_web/templates/password/edit.html.slime @@ -1,6 +1,6 @@ h1 Reset password -= form_for @changeset, Routes.password_path(@conn, :update, @token), fn f -> += form_for @changeset, ~p"/passwords/#{@token}", fn f -> = if @changeset.action do .alert.alert-danger p Oops, something went wrong! Please check the errors below. diff --git a/lib/philomena_web/templates/password/new.html.slime b/lib/philomena_web/templates/password/new.html.slime index 20b84e85..3aac61b5 100644 --- a/lib/philomena_web/templates/password/new.html.slime +++ b/lib/philomena_web/templates/password/new.html.slime @@ -3,7 +3,7 @@ p ' Provide the email address you signed up with and we will email you ' password reset instructions. -= form_for :user, Routes.password_path(@conn, :create), fn f -> += form_for :user, ~p"/passwords", fn f -> .field = email_input f, :email, class: "input", placeholder: "Email", required: true diff --git a/lib/philomena_web/templates/post/_post.html.slime b/lib/philomena_web/templates/post/_post.html.slime index d6f5c6a8..fc41fa73 100644 --- a/lib/philomena_web/templates/post/_post.html.slime +++ b/lib/philomena_web/templates/post/_post.html.slime @@ -9,7 +9,7 @@ article.block.communication id="post_#{@post.id}" p ul.horizontal-list li - = link(to: Routes.forum_topic_post_approve_path(@conn, :create, @post.topic.forum, @post.topic, @post), data: [confirm: "Are you sure?"], method: "post", class: "button") do + = link(to: ~p"/forums/#{@post.topic.forum}/topics/#{@post.topic}/posts/#{@post}/approve", data: [confirm: "Are you sure?"], method: "post", class: "button") do i.fas.fa-check> ' Approve li @@ -17,7 +17,7 @@ article.block.communication id="post_#{@post.id}" i.fa.fa-times> ' Reject - = form_for :post, Routes.forum_topic_post_hide_path(@conn, :create, @post.topic.forum, @post.topic, @post), [class: "togglable-delete-form hidden flex", id: "inline-reject-form-post-#{@post.id}"], fn f -> + = form_for :post, ~p"/forums/#{@post.topic.forum}/topics/#{@post.topic}/posts/#{@post}/hide", [class: "togglable-delete-form hidden flex", id: "inline-reject-form-post-#{@post.id}"], fn f -> = text_input f, :deletion_reason, class: "input input--wide", placeholder: "Deletion Reason", id: "inline-reject-reason-post-#{@post.id}", required: true = submit "Delete", class: "button" @@ -57,11 +57,11 @@ article.block.communication id="post_#{@post.id}" = if can?(@conn, :hide, @post) and not hide_staff_tools?(@conn) do = cond do - @post.hidden_from_users and not @post.destroyed_content -> - = link(to: Routes.forum_topic_post_hide_path(@conn, :delete, @post.topic.forum, @post.topic, @post), data: [confirm: "Are you sure?"], method: "delete", class: "communication__interaction") do + = link(to: ~p"/forums/#{@post.topic.forum}/topics/#{@post.topic}/posts/#{@post}/hide", data: [confirm: "Are you sure?"], method: "delete", class: "communication__interaction") do i.fas.fa-check> ' Restore = if can?(@conn, :delete, @post) do - = link(to: Routes.forum_topic_post_delete_path(@conn, :create, @post.topic.forum, @post.topic, @post), data: [confirm: "Are you sure?"], method: "post", class: "communication__interaction") do + = link(to: ~p"/forums/#{@post.topic.forum}/topics/#{@post.topic}/posts/#{@post}/delete", data: [confirm: "Are you sure?"], method: "post", class: "communication__interaction") do i.fas.fa-times> ' Delete Contents @@ -78,6 +78,6 @@ article.block.communication id="post_#{@post.id}" .communication__info =<> link_to_fingerprint(@conn, @post.fingerprint) - = form_for :post, Routes.forum_topic_post_hide_path(@conn, :create, @post.topic.forum, @post.topic, @post), [class: "togglable-delete-form hidden flex", id: "inline-del-form-post-#{@post.id}"], fn f -> + = form_for :post, ~p"/forums/#{@post.topic.forum}/topics/#{@post.topic}/posts/#{@post}/hide", [class: "togglable-delete-form hidden flex", id: "inline-del-form-post-#{@post.id}"], fn f -> = text_input f, :deletion_reason, class: "input input--wide", placeholder: "Deletion Reason", id: "inline-del-reason-post-#{@post.id}", required: true = submit "Delete", class: "button" diff --git a/lib/philomena_web/templates/post/_post_options.html.slime b/lib/philomena_web/templates/post/_post_options.html.slime index f17212b8..214cf1d3 100644 --- a/lib/philomena_web/templates/post/_post_options.html.slime +++ b/lib/philomena_web/templates/post/_post_options.html.slime @@ -2,13 +2,13 @@ div ' Posted => pretty_time(@post.created_at) - a.communication__interaction href=Routes.forum_topic_post_report_path(@conn, :new, @post.topic.forum, @post.topic, @post) + a.communication__interaction href=~p"/forums/#{@post.topic.forum}/topics/#{@post.topic}/posts/#{@post}/reports/new" i.fa.fa-flag> ' Report = if not is_nil(@post.edited_at) and can?(@conn, :show, @post) do br - a href=Routes.forum_topic_post_history_path(@conn, :index, @post.topic.forum, @post.topic, @post) + a href=~p"/forums/#{@post.topic.forum}/topics/#{@post.topic}/posts/#{@post}/history" ' Edited => pretty_time(@post.edited_at) @@ -17,7 +17,7 @@ div => @post.edit_reason div - - link_path = Routes.forum_topic_path(@conn, :show, @post.topic.forum, @post.topic, post_id: @post.id) <> "#post_#{@post.id}" + - link_path = ~p"/forums/#{@post.topic.forum}/topics/#{@post.topic}?#{[post_id: @post.id]}" <> "#post_#{@post.id}" - safe_author = markdown_safe_author(@post) - quote_body = if @post.hidden_from_users, do: "", else: @post.body @@ -36,6 +36,6 @@ div = if can?(@conn, :edit, @post) do span.owner-options strong - a.communication__interaction href=Routes.forum_topic_post_path(@conn, :edit, @post.topic.forum, @post.topic, @post) + a.communication__interaction href=~p"/forums/#{@post.topic.forum}/topics/#{@post.topic}/posts/#{@post}/edit" i.fas.fa-edit> ' Edit diff --git a/lib/philomena_web/templates/post/index.html.slime b/lib/philomena_web/templates/post/index.html.slime index 507fbd69..6313a9dc 100644 --- a/lib/philomena_web/templates/post/index.html.slime +++ b/lib/philomena_web/templates/post/index.html.slime @@ -1,6 +1,6 @@ h1 Posts -= form_for :posts, Routes.post_path(@conn, :index), [method: "get", class: "hform", enforce_utf8: false], fn f -> += form_for :posts, ~p"/posts", [method: "get", class: "hform", enforce_utf8: false], fn f -> .field = text_input f, :pq, name: :pq, value: @conn.params["pq"], class: "input hform__text", placeholder: "Search posts", autocapitalize: "none" = submit "Search", class: "hform__button button" @@ -14,17 +14,17 @@ h2 Search Results = cond do - Enum.any?(@posts) -> - - route = fn p -> Routes.post_path(@conn, :index, p) end + - route = fn p -> ~p"/posts?#{p}" end - pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @posts, route: route, params: [pq: @conn.params["pq"]], conn: @conn = for {body, post} <- @posts, post.topic.hidden_from_users == false do div h3 - =<> link post.topic.forum.name, to: Routes.forum_path(@conn, :show, post.topic.forum) + =<> link post.topic.forum.name, to: ~p"/forums/#{post.topic.forum}" | » - =<> link post.topic.title, to: Routes.forum_topic_path(@conn, :show, post.topic.forum, post.topic) + =<> link post.topic.title, to: ~p"/forums/#{post.topic.forum}/topics/#{post.topic}" | » - - post_link = Routes.forum_topic_path(@conn, :show, post.topic.forum, post.topic, post_id: post.id) <> "#post_#{post.id}" + - post_link = ~p"/forums/#{post.topic.forum}/topics/#{post.topic}?#{[post_id: post.id]}" <> "#post_#{post.id}" = if post.topic_position == 0 do =<> link "Topic Opener", to: post_link - else @@ -79,28 +79,28 @@ table.table td Literal td Matches the author of this post. Anonymous authors will never match this term. td - code = link "author:Joey", to: Routes.post_path(@conn, :index, pq: "author:Joey") + code = link "author:Joey", to: ~p"/posts?#{[pq: "author:Joey"]}" tr td code body td Full Text td Matches the body of this post. This is the default field. td - code = link "body:test", to: Routes.post_path(@conn, :index, pq: "body:test") + code = link "body:test", to: ~p"/posts?#{[pq: "body:test"]}" tr td code created_at td Date/Time Range td Matches the creation time of this post. td - code = link "created_at:2015", to: Routes.post_path(@conn, :index, pq: "created_at:2015") + code = link "created_at:2015", to: ~p"/posts?#{[pq: "created_at:2015"]}" tr td code id td Numeric Range td Matches the numeric surrogate key for this post. td - code = link "id:1000000", to: Routes.post_path(@conn, :index, pq: "id:1000000") + code = link "id:1000000", to: ~p"/posts?#{[pq: "id:1000000"]}" tr td code my @@ -109,46 +109,46 @@ table.table code> my:posts ' matches posts you have posted if you are signed in. td - code = link "my:posts", to: Routes.post_path(@conn, :index, pq: "my:posts") + code = link "my:posts", to: ~p"/posts?#{[pq: "my:posts"]}" tr td code subject td Full Text td Matches the title of the topic. td - code = link "subject:time wasting thread", to: Routes.post_path(@conn, :index, pq: "subject:time wasting thread") + code = link "subject:time wasting thread", to: ~p"/posts?#{[pq: "subject:time wasting thread"]}" tr td code topic_id td Literal td Matches the numeric surrogate key for the topic this post belongs to. td - code = link "topic_id:7000", to: Routes.post_path(@conn, :index, pq: "topic_id:7000") + code = link "topic_id:7000", to: ~p"/posts?#{[pq: "topic_id:7000"]}" tr td code topic_position td Numeric Range td Matches the offset from the beginning of the topic of this post. Positions begin at 0. td - code = link "topic_position:0", to: Routes.post_path(@conn, :index, pq: "topic_position:0") + code = link "topic_position:0", to: ~p"/posts?#{[pq: "topic_position:0"]}" tr td code updated_at td Date/Time Range td Matches the creation or last edit time of this post. td - code = link "updated_at.gte:2 weeks ago", to: Routes.post_path(@conn, :index, pq: "updated_at.gte:2 weeks ago") + code = link "updated_at.gte:2 weeks ago", to: ~p"/posts?#{[pq: "updated_at.gte:2 weeks ago"]}" tr td code user_id td Literal td Matches posts with the specified user_id. Anonymous users will never match this term. td - code = link "user_id:211190", to: Routes.post_path(@conn, :index, pq: "user_id:211190") + code = link "user_id:211190", to: ~p"/posts?#{[pq: "user_id:211190"]}" tr td code forum td Literal td Matches the short name for the forum this post belongs to. td - code = link "forum:meta", to: Routes.post_path(@conn, :index, pq: "forum:meta") + code = link "forum:meta", to: ~p"/posts?#{[pq: "forum:meta"]}" diff --git a/lib/philomena_web/templates/profile/_about_me.html.slime b/lib/philomena_web/templates/profile/_about_me.html.slime index e4c4a782..5bad35b2 100644 --- a/lib/philomena_web/templates/profile/_about_me.html.slime +++ b/lib/philomena_web/templates/profile/_about_me.html.slime @@ -6,6 +6,6 @@ - current?(@user, @conn.assigns.current_user) -> em ' Want to - => link "add some info about yourself?", to: Routes.profile_description_path(@conn, :edit, @user) + => link "add some info about yourself?", to: ~p"/profiles/#{@user}/description/edit" - true -> diff --git a/lib/philomena_web/templates/profile/_admin_block.html.slime b/lib/philomena_web/templates/profile/_admin_block.html.slime index 187772d2..ca2462ab 100644 --- a/lib/philomena_web/templates/profile/_admin_block.html.slime +++ b/lib/philomena_web/templates/profile/_admin_block.html.slime @@ -7,7 +7,7 @@ i.fa.fa-fw.fa-filter> ' Current Filter: = if @filter do - = link @filter.name, to: Routes.filter_path(@conn, :show, @filter) + = link @filter.name, to: ~p"/filters/#{@filter}" - else em ' (none) @@ -52,127 +52,127 @@ a.label.label--primary.label--block href="#" data-click-toggle=".js-admin__optio .profile-top__options.js-admin__options__toggle.hidden ul.profile-admin__options__column li - = link to: Routes.profile_detail_path(@conn, :index, @user) do + = link to: ~p"/profiles/#{@user}/details" do i.fa.fa-fw.fa-eye span.admin__button View Details li - = link to: Routes.search_path(@conn, :index, q: "upvoted_by_id:#{@user.id}") do + = link to: ~p"/search?#{[q: "upvoted_by_id:#{@user.id}"]}" do i.fa.fa-fw.fa-arrow-up span.admin__button Upvotes li - = link to: Routes.search_path(@conn, :index, q: "downvoted_by_id:#{@user.id}") do + = link to: ~p"/search?#{[q: "downvoted_by_id:#{@user.id}"]}" do i.fa.fa-fw.fa-arrow-down span.admin__button Downvotes li - = link to: Routes.search_path(@conn, :index, q: "hidden_by_id:#{@user.id}") do + = link to: ~p"/search?#{[q: "hidden_by_id:#{@user.id}"]}" do i.fa.fa-fw.fa-eye-slash span.admin__button Hidden Images li - = link to: Routes.admin_report_path(@conn, :index, rq: "user_id:#{@user.id}") do + = link to: ~p"/admin/reports?#{[rq: "user_id:#{@user.id}"]}" do i.fa.fa-fw.fa-exclamation span.admin__button Reports li - = link to: Routes.profile_ip_history_path(@conn, :index, @user) do + = link to: ~p"/profiles/#{@user}/ip_history" do i.fab.fa-fw.fa-internet-explorer span.admin__button IP History li - = link to: Routes.profile_fp_history_path(@conn, :index, @user) do + = link to: ~p"/profiles/#{@user}/fp_history" do i.fa.fa-fw.fa-desktop span.admin__button FP History li - = link to: Routes.profile_alias_path(@conn, :index, @user) do + = link to: ~p"/profiles/#{@user}/aliases" do i.fa.fa-fw.fa-users span.admin__button Potential Aliases = if can?(@conn, :index, %Philomena.Donations.Donation{}) do li - = link to: Routes.admin_donation_user_path(@conn, :show, @user) do + = link to: ~p"/admin/donations/user/#{@user}" do i.fas.fa-fw.fa-dollar-sign span.admin__button Donations ul.profile-admin__options__column = if can?(@conn, :edit, @user) do li - = link to: Routes.admin_user_path(@conn, :edit, @user) do + = link to: ~p"/admin/users/#{@user}/edit" do i.fas.fa-fw.fa-edit span.admin__button Edit User li - = link to: Routes.admin_user_force_filter_path(@conn, :new, @user) do + = link to: ~p"/admin/users/#{@user}/force_filter/new" do i.fas.faw-fw.fa-filter span.admin__button Force Filter = if @forced do li - = link to: Routes.admin_user_force_filter_path(@conn, :delete, @user), data: [confirm: "Are you really, really sure?", method: "delete"] do + = link to: ~p"/admin/users/#{@user}/force_filter", data: [confirm: "Are you really, really sure?", method: "delete"] do i.fas.fa-fw.fa-filter span.admin__button Remove Force Filter = if @user.deleted_at do li - = link to: Routes.admin_user_activation_path(@conn, :create, @user), data: [confirm: "Are you really, really sure?", method: "post"] do + = link to: ~p"/admin/users/#{@user}/activation", data: [confirm: "Are you really, really sure?", method: "post"] do i.fa.fa-fw.fa-check span.admin__button Reactivate Account - else li - = link to: Routes.admin_user_activation_path(@conn, :delete, @user), data: [confirm: "Are you really, really sure?", method: "delete"] do + = link to: ~p"/admin/users/#{@user}/activation", data: [confirm: "Are you really, really sure?", method: "delete"] do i.fa.fa-fw.fa-times span.admin__button Deactivate Account = if @user.locked_at do li - = link to: Routes.admin_user_unlock_path(@conn, :create, @user), data: [method: "post"] do + = link to: ~p"/admin/users/#{@user}/unlock", data: [method: "post"] do i.fas.fa-fw.fa-unlock span.admin__button Unlock Account li - = link to: Routes.admin_user_wipe_path(@conn, :create, @user), data: [confirm: "This is irreversible, destroying all identifying information including email. Are you sure?", method: "post"] do + = link to: ~p"/admin/users/#{@user}/wipe", data: [confirm: "This is irreversible, destroying all identifying information including email. Are you sure?", method: "post"] do i.fas.fa-fw.fa-eraser span.admin__button Wipe PII = if can?(@conn, :edit, %Philomena.ArtistLinks.ArtistLink{}) do li - = link to: Routes.profile_artist_link_path(@conn, :new, @user) do + = link to: ~p"/profiles/#{@user}/artist_links/new" do i.fa.fa-fw.fa-link span.admin__button Add Artist Link = if can?(@conn, :create, Philomena.Bans.User) do li - = link to: Routes.admin_user_ban_path(@conn, :new, username: @user.name) do + = link to: ~p"/admin/user_bans/new?#{[username: @user.name]}" do i.fa.fa-fw.fa-ban span.admin__button Ban this sucker ul.profile-admin__options__column = if can?(@conn, :index, Philomena.Users.User) do li - = link to: Routes.admin_user_api_key_path(@conn, :delete, @user), data: [confirm: "Are you really, really sure?", method: "delete"] do + = link to: ~p"/admin/users/#{@user}/api_key", data: [confirm: "Are you really, really sure?", method: "delete"] do i.fas.fa-fw.fa-key span.admin__button Reset API key li = if @user.verified do - = link to: Routes.admin_user_verification_path(@conn, :delete, @user), data: [confirm: "Are you really, really sure?", method: "delete"] do + = link to: ~p"/admin/users/#{@user}/verification", data: [confirm: "Are you really, really sure?", method: "delete"] do i.fas.fa-fw.fa-user-times span.admin__button Revoke Verification - else - = link to: Routes.admin_user_verification_path(@conn, :create, @user), data: [confirm: "Are you really, really sure?", method: "create"] do + = link to: ~p"/admin/users/#{@user}/verification", data: [confirm: "Are you really, really sure?", method: "create"] do i.fas.fa-fw.fa-user-check span.admin__button Grant Verification ul.profile-admin__options__column = if can?(@conn, :index, Philomena.Users.User) do li - = link to: Routes.admin_user_vote_path(@conn, :delete, @user), data: [confirm: "Are you really, really sure?", method: "delete"] do + = link to: ~p"/admin/users/#{@user}/votes", data: [confirm: "Are you really, really sure?", method: "delete"] do i.far.fa-fw.fa-file-excel span.admin__button Remove All Votes/Faves li - = link to: Routes.admin_user_downvote_path(@conn, :delete, @user), data: [confirm: "Are you really, really sure?", method: "delete"] do + = link to: ~p"/admin/users/#{@user}/downvotes", data: [confirm: "Are you really, really sure?", method: "delete"] do i.fa.fa-fw.fa-arrow-down span.admin__button Remove All Downvotes = if @user.role == "user" and can?(@conn, :revert, Philomena.TagChanges.TagChange) do li - = link to: Routes.tag_change_full_revert_path(@conn, :create, [user_id: @user.id]), data: [confirm: "Are you really, really sure?", method: "create"] do + = link to: ~p"/tag_changes/full_revert?#{[user_id: @user.id]}", data: [confirm: "Are you really, really sure?", method: "create"] do i.fa.fa-fw.fa-tag span.admin__button Revert All Tag Changes diff --git a/lib/philomena_web/templates/profile/_commission.html.slime b/lib/philomena_web/templates/profile/_commission.html.slime index db8e8d46..be102740 100644 --- a/lib/philomena_web/templates/profile/_commission.html.slime +++ b/lib/philomena_web/templates/profile/_commission.html.slime @@ -21,18 +21,18 @@ br br - = link "More information", to: Routes.profile_commission_path(@conn, :show, @user) + = link "More information", to: ~p"/profiles/#{@user}/commission" - current?(@user, @conn.assigns.current_user) -> = if Enum.any?(@conn.assigns.user.verified_links) do em ' You don't have any commission information listed yet. - => link "Click here", to: Routes.profile_commission_path(@conn, :new, @user) + => link "Click here", to: ~p"/profiles/#{@user}/commission/new" ' to set it up. - else em ' You must have a verified Artist Link to create a commission page. - => link "Click here", to: Routes.profile_artist_link_path(@conn, :new, @user) + => link "Click here", to: ~p"/profiles/#{@user}/artist_links/new" ' to set one up. - true -> diff --git a/lib/philomena_web/templates/profile/_recent_comments.html.slime b/lib/philomena_web/templates/profile/_recent_comments.html.slime index 02f460a0..2752b333 100644 --- a/lib/philomena_web/templates/profile/_recent_comments.html.slime +++ b/lib/philomena_web/templates/profile/_recent_comments.html.slime @@ -2,7 +2,7 @@ .block .block__header span.block__header__title Recent Comments - = link "View all", to: Routes.comment_path(@conn, :index, cq: "user_id:#{@user.id}") + = link "View all", to: ~p"/comments?#{[cq: "user_id:#{@user.id}"]}" .block__content = for {body, comment} <- @comments, can?(@conn, :show, comment.image) do diff --git a/lib/philomena_web/templates/profile/_recent_galleries.html.slime b/lib/philomena_web/templates/profile/_recent_galleries.html.slime index d67f1061..8aee5f98 100644 --- a/lib/philomena_web/templates/profile/_recent_galleries.html.slime +++ b/lib/philomena_web/templates/profile/_recent_galleries.html.slime @@ -2,7 +2,7 @@ .block .block__header span.block__header__title Recent Galleries - = link "View all", to: Routes.gallery_path(@conn, :index, gallery: [creator: @user.name]) + = link "View all", to: ~p"/galleries?#{[gallery: [creator: @user.name]]}" .block__content.js-resizable-media-container = for gallery <- @galleries do diff --git a/lib/philomena_web/templates/profile/_recent_posts.html.slime b/lib/philomena_web/templates/profile/_recent_posts.html.slime index c7b91658..3b4b4814 100644 --- a/lib/philomena_web/templates/profile/_recent_posts.html.slime +++ b/lib/philomena_web/templates/profile/_recent_posts.html.slime @@ -2,13 +2,13 @@ .block .block__header span.block__header__title Recent Forum Posts - = link "View all", to: Routes.post_path(@conn, :index, pq: "user_id:#{@user.id}") + = link "View all", to: ~p"/posts?#{[pq: "user_id:#{@user.id}"]}" .block__content .block = for post <- @posts do .block__content.alternating-color ' Post - => link pretty_time(post.created_at), to: Routes.forum_topic_path(@conn, :show, post.topic.forum, post.topic, post_id: post) <> "#post_#{post.id}" + => link pretty_time(post.created_at), to: ~p"/forums/#{post.topic.forum}/topics/#{post.topic}?#{[post_id: post]}" <> "#post_#{post.id}" ' in topic - => link post.topic.title, to: Routes.forum_topic_path(@conn, :show, post.topic.forum, post.topic) + => link post.topic.title, to: ~p"/forums/#{post.topic.forum}/topics/#{post.topic}" diff --git a/lib/philomena_web/templates/profile/alias/_aliases.html.slime b/lib/philomena_web/templates/profile/alias/_aliases.html.slime index 53913aad..38030e40 100644 --- a/lib/philomena_web/templates/profile/alias/_aliases.html.slime +++ b/lib/philomena_web/templates/profile/alias/_aliases.html.slime @@ -1,7 +1,7 @@ = for u <- @aliases do tr td - = link u.name, to: Routes.profile_path(@conn, :show, u) + = link u.name, to: ~p"/profiles/#{u}" td = @type diff --git a/lib/philomena_web/templates/profile/artist_link/edit.html.slime b/lib/philomena_web/templates/profile/artist_link/edit.html.slime index 7c643cf4..c03ff454 100644 --- a/lib/philomena_web/templates/profile/artist_link/edit.html.slime +++ b/lib/philomena_web/templates/profile/artist_link/edit.html.slime @@ -1,2 +1,2 @@ h1 Edit Link -= render PhilomenaWeb.Profile.ArtistLinkView, "_form.html", conn: @conn, changeset: @changeset, tag_name: tag_name(@artist_link), action: Routes.profile_artist_link_path(@conn, :update, @artist_link.user, @artist_link) += render PhilomenaWeb.Profile.ArtistLinkView, "_form.html", conn: @conn, changeset: @changeset, tag_name: tag_name(@artist_link), action: ~p"/profiles/#{@artist_link.user}/artist_links/#{@artist_link}" diff --git a/lib/philomena_web/templates/profile/artist_link/index.html.slime b/lib/philomena_web/templates/profile/artist_link/index.html.slime index 15f2999b..7cb3be11 100644 --- a/lib/philomena_web/templates/profile/artist_link/index.html.slime +++ b/lib/philomena_web/templates/profile/artist_link/index.html.slime @@ -1,6 +1,6 @@ h1 Artist Links p - a.button href=Routes.profile_artist_link_path(@conn, :new, @user) + a.button href=~p"/profiles/#{@user}/artist_links/new" ' Request a link p ' Artist links associate your account on Derpibooru with tags about content you create and with accounts on sites elsewhere. This allows users to easily identify artists and staff to act more rapidly on takedown requests. @@ -17,7 +17,7 @@ table.table = for link <- @artist_links do tr td = link link.uri, to: link.uri - td = link "View Details", to: Routes.profile_artist_link_path(@conn, :show, @user, link) + td = link "View Details", to: ~p"/profiles/#{@user}/artist_links/#{link}" td = link.verification_code th = verified_as_string(link) th = public_as_string(link) diff --git a/lib/philomena_web/templates/profile/artist_link/new.html.slime b/lib/philomena_web/templates/profile/artist_link/new.html.slime index 762d9be9..a2566378 100644 --- a/lib/philomena_web/templates/profile/artist_link/new.html.slime +++ b/lib/philomena_web/templates/profile/artist_link/new.html.slime @@ -1,2 +1,2 @@ h1 Request Artist Link -= render PhilomenaWeb.Profile.ArtistLinkView, "_form.html", changeset: @changeset, action: Routes.profile_artist_link_path(@conn, :create, @user), conn: @conn += render PhilomenaWeb.Profile.ArtistLinkView, "_form.html", changeset: @changeset, action: ~p"/profiles/#{@user}/artist_links", conn: @conn diff --git a/lib/philomena_web/templates/profile/artist_link/show.html.slime b/lib/philomena_web/templates/profile/artist_link/show.html.slime index d38133d4..73aedd3f 100644 --- a/lib/philomena_web/templates/profile/artist_link/show.html.slime +++ b/lib/philomena_web/templates/profile/artist_link/show.html.slime @@ -54,16 +54,16 @@ h3 Associated tag = if can?(@conn, :index, Philomena.ArtistLinks.ArtistLink) do p - => link "Edit", to: Routes.profile_artist_link_path(@conn, :edit, @user, @artist_link) + => link "Edit", to: ~p"/profiles/#{@user}/artist_links/#{@artist_link}/edit" ' • - => link "Verify", to: Routes.admin_artist_link_verification_path(@conn, :create, @artist_link), method: :post + => link "Verify", to: ~p"/admin/artist_links/#{@artist_link}/verification", method: :post ' • - => link "Reject", to: Routes.admin_artist_link_reject_path(@conn, :create, @artist_link), method: :post + => link "Reject", to: ~p"/admin/artist_links/#{@artist_link}/reject", method: :post = if not verified?(@artist_link) do ' • = if contacted?(@artist_link) do ' Artist contacted - else - = link "Artist contacted", to: Routes.admin_artist_link_contact_path(@conn, :create, @artist_link), method: :post + = link "Artist contacted", to: ~p"/admin/artist_links/#{@artist_link}/contact", method: :post -= link "Back", to: Routes.profile_artist_link_path(@conn, :index, @user) += link "Back", to: ~p"/profiles/#{@user}/artist_links" diff --git a/lib/philomena_web/templates/profile/award/edit.html.slime b/lib/philomena_web/templates/profile/award/edit.html.slime index 0216955e..94a5f3b6 100644 --- a/lib/philomena_web/templates/profile/award/edit.html.slime +++ b/lib/philomena_web/templates/profile/award/edit.html.slime @@ -1,3 +1,3 @@ h1 Editing award -= render PhilomenaWeb.Profile.AwardView, "_form.html", changeset: @changeset, badges: @badges, action: Routes.profile_award_path(@conn, :update, @user, @award), conn: @conn += render PhilomenaWeb.Profile.AwardView, "_form.html", changeset: @changeset, badges: @badges, action: ~p"/profiles/#{@user}/awards/#{@award}", conn: @conn diff --git a/lib/philomena_web/templates/profile/award/new.html.slime b/lib/philomena_web/templates/profile/award/new.html.slime index 489bc93e..525e06cf 100644 --- a/lib/philomena_web/templates/profile/award/new.html.slime +++ b/lib/philomena_web/templates/profile/award/new.html.slime @@ -1,3 +1,3 @@ h1 New award -= render PhilomenaWeb.Profile.AwardView, "_form.html", changeset: @changeset, badges: @badges, action: Routes.profile_award_path(@conn, :create, @user), conn: @conn += render PhilomenaWeb.Profile.AwardView, "_form.html", changeset: @changeset, badges: @badges, action: ~p"/profiles/#{@user}/awards", conn: @conn diff --git a/lib/philomena_web/templates/profile/commission/_listing_items.html.slime b/lib/philomena_web/templates/profile/commission/_listing_items.html.slime index 778daa01..49ead871 100644 --- a/lib/philomena_web/templates/profile/commission/_listing_items.html.slime +++ b/lib/philomena_web/templates/profile/commission/_listing_items.html.slime @@ -3,7 +3,7 @@ span.block__header__title Available Items and Prices = if current?(@user, @conn.assigns.current_user) do - = link "Add an item", to: Routes.profile_commission_item_path(@conn, :new, @user) + = link "Add an item", to: ~p"/profiles/#{@user}/commission/items/new" .block__content @@ -12,7 +12,7 @@ p You have not added any items to your commissions sheet yet. p ' Your listing will not appear in search results until you - = link "list at least one item", to: Routes.profile_commission_item_path(@conn, :new, @user) + = link "list at least one item", to: ~p"/profiles/#{@user}/commission/items/new" ' . - else p This artist has not added any items yet. Please check back later. @@ -52,7 +52,7 @@ = if can?(@conn, :edit, @commission) do td - = link "Edit item", to: Routes.profile_commission_item_path(@conn, :edit, @user, item) + = link "Edit item", to: ~p"/profiles/#{@user}/commission/items/#{item}/edit" br br - = link "Delete item", to: Routes.profile_commission_item_path(@conn, :delete, @user, item), data: [confirm: "Are you really, really sure?", method: "delete"] + = link "Delete item", to: ~p"/profiles/#{@user}/commission/items/#{item}", data: [confirm: "Are you really, really sure?", method: "delete"] diff --git a/lib/philomena_web/templates/profile/commission/_listing_sidebar.html.slime b/lib/philomena_web/templates/profile/commission/_listing_sidebar.html.slime index 544ed939..93db5128 100644 --- a/lib/philomena_web/templates/profile/commission/_listing_sidebar.html.slime +++ b/lib/philomena_web/templates/profile/commission/_listing_sidebar.html.slime @@ -71,18 +71,18 @@ span.block__header__title Options .block__content = if can?(@conn, :edit, @commission) do - = link "Edit this listing", to: Routes.profile_commission_path(@conn, :edit, @user) + = link "Edit this listing", to: ~p"/profiles/#{@user}/commission/edit" br - = link "Delete this listing", to: Routes.profile_commission_path(@conn, :delete, @user), data: [confirm: "Are you really, really sure about that?", method: "delete"] + = link "Delete this listing", to: ~p"/profiles/#{@user}/commission", data: [confirm: "Are you really, really sure about that?", method: "delete"] br - = link "Report this listing", to: Routes.profile_commission_report_path(@conn, :new, @user) + = link "Report this listing", to: ~p"/profiles/#{@user}/commission/reports/new" / Share block .block .block__header span.block__header__title Share this listing .block__content - - url = Routes.profile_commission_url(@conn, :show, @user) + - url = url(~p"/profiles/#{@user}/commission") .field label> for="commission_url" URL diff --git a/lib/philomena_web/templates/profile/commission/edit.html.slime b/lib/philomena_web/templates/profile/commission/edit.html.slime index aa6bab71..514d03f0 100644 --- a/lib/philomena_web/templates/profile/commission/edit.html.slime +++ b/lib/philomena_web/templates/profile/commission/edit.html.slime @@ -1,5 +1,5 @@ h1 Edit Commission Listing p - = link "Back to commission", to: Routes.profile_commission_path(@conn, :show, @user) + = link "Back to commission", to: ~p"/profiles/#{@user}/commission" -= render PhilomenaWeb.Profile.CommissionView, "_form.html", changeset: @changeset, action: Routes.profile_commission_path(@conn, :update, @user), conn: @conn \ No newline at end of file += render PhilomenaWeb.Profile.CommissionView, "_form.html", changeset: @changeset, action: ~p"/profiles/#{@user}/commission", conn: @conn \ No newline at end of file diff --git a/lib/philomena_web/templates/profile/commission/item/edit.html.slime b/lib/philomena_web/templates/profile/commission/item/edit.html.slime index cb8124be..46d4e28b 100644 --- a/lib/philomena_web/templates/profile/commission/item/edit.html.slime +++ b/lib/philomena_web/templates/profile/commission/item/edit.html.slime @@ -1,5 +1,5 @@ h1 Edit Item on Listing p - = link "Back to listing", to: Routes.profile_commission_path(@conn, :show, @user) + = link "Back to listing", to: ~p"/profiles/#{@user}/commission" -= render PhilomenaWeb.Profile.Commission.ItemView, "_form.html", conn: @conn, changeset: @changeset, action: Routes.profile_commission_item_path(@conn, :update, @user, @item) += render PhilomenaWeb.Profile.Commission.ItemView, "_form.html", conn: @conn, changeset: @changeset, action: ~p"/profiles/#{@user}/commission/items/#{@item}" diff --git a/lib/philomena_web/templates/profile/commission/item/new.html.slime b/lib/philomena_web/templates/profile/commission/item/new.html.slime index b2a75690..6897a066 100644 --- a/lib/philomena_web/templates/profile/commission/item/new.html.slime +++ b/lib/philomena_web/templates/profile/commission/item/new.html.slime @@ -1,5 +1,5 @@ h1 New Item on Listing p - = link "Back to listing", to: Routes.profile_commission_path(@conn, :show, @user) + = link "Back to listing", to: ~p"/profiles/#{@user}/commission" -= render PhilomenaWeb.Profile.Commission.ItemView, "_form.html", conn: @conn, changeset: @changeset, action: Routes.profile_commission_item_path(@conn, :create, @user) += render PhilomenaWeb.Profile.Commission.ItemView, "_form.html", conn: @conn, changeset: @changeset, action: ~p"/profiles/#{@user}/commission/items" diff --git a/lib/philomena_web/templates/profile/commission/new.html.slime b/lib/philomena_web/templates/profile/commission/new.html.slime index 98653d8d..0e08e263 100644 --- a/lib/philomena_web/templates/profile/commission/new.html.slime +++ b/lib/philomena_web/templates/profile/commission/new.html.slime @@ -1,5 +1,5 @@ h1 New Commission Listing p - = link "Back to index", to: Routes.commission_path(@conn, :index) + = link "Back to index", to: ~p"/commissions" -= render PhilomenaWeb.Profile.CommissionView, "_form.html", changeset: @changeset, action: Routes.profile_commission_path(@conn, :create, @user), conn: @conn \ No newline at end of file += render PhilomenaWeb.Profile.CommissionView, "_form.html", changeset: @changeset, action: ~p"/profiles/#{@user}/commission", conn: @conn \ No newline at end of file diff --git a/lib/philomena_web/templates/profile/description/edit.html.slime b/lib/philomena_web/templates/profile/description/edit.html.slime index bc09393a..a59ced13 100644 --- a/lib/philomena_web/templates/profile/description/edit.html.slime +++ b/lib/philomena_web/templates/profile/description/edit.html.slime @@ -1,6 +1,6 @@ h1 Updating Profile Description -= form_for @changeset, Routes.profile_description_path(@conn, :update, @user), [method: "put"], fn f -> += form_for @changeset, ~p"/profiles/#{@user}/description", [method: "put"], fn f -> = if @changeset.action do .alert.alert-danger p Oops, something went wrong! Please check the errors below. diff --git a/lib/philomena_web/templates/profile/detail/index.html.slime b/lib/philomena_web/templates/profile/detail/index.html.slime index 2384a855..7d51cdfc 100644 --- a/lib/philomena_web/templates/profile/detail/index.html.slime +++ b/lib/philomena_web/templates/profile/detail/index.html.slime @@ -1,10 +1,10 @@ h2 - = link @user.name, to: Routes.profile_path(@conn, :show, @user) + = link @user.name, to: ~p"/profiles/#{@user}" | 's User Details h4 Mod Notes = render PhilomenaWeb.Admin.ModNoteView, "_table.html", mod_notes: @mod_notes, conn: @conn -= link "Add New Note", to: Routes.admin_mod_note_path(@conn, :new, notable_id: @user.id, notable_type: "User") += link "Add New Note", to: ~p"/admin/mod_notes/new?#{[notable_id: @user.id, notable_type: "User"]}" h4 Name History table.table @@ -20,6 +20,6 @@ table.table h4 More Details ul - li = link "IP Address Usage History", to: Routes.profile_ip_history_path(@conn, :index, @user) - li = link "Fingerprint Usage History", to: Routes.profile_fp_history_path(@conn, :index, @user) - li = link "Potential Aliases", to: Routes.profile_alias_path(@conn, :index, @user) + li = link "IP Address Usage History", to: ~p"/profiles/#{@user}/ip_history" + li = link "Fingerprint Usage History", to: ~p"/profiles/#{@user}/fp_history" + li = link "Potential Aliases", to: ~p"/profiles/#{@user}/aliases" diff --git a/lib/philomena_web/templates/profile/fp_history/index.html.slime b/lib/philomena_web/templates/profile/fp_history/index.html.slime index b67a9e3c..182c30c5 100644 --- a/lib/philomena_web/templates/profile/fp_history/index.html.slime +++ b/lib/philomena_web/templates/profile/fp_history/index.html.slime @@ -10,7 +10,7 @@ ul ul = for u <- @other_users[ufp.fingerprint] do li - => link u.user.name, to: Routes.profile_path(@conn, :show, u.user) + => link u.user.name, to: ~p"/profiles/#{u.user}" | ( => u.uses ' uses, last used diff --git a/lib/philomena_web/templates/profile/ip_history/index.html.slime b/lib/philomena_web/templates/profile/ip_history/index.html.slime index 3d494d78..d5ffc0ff 100644 --- a/lib/philomena_web/templates/profile/ip_history/index.html.slime +++ b/lib/philomena_web/templates/profile/ip_history/index.html.slime @@ -10,7 +10,7 @@ ul ul = for u <- @other_users[uip.ip] do li - => link u.user.name, to: Routes.profile_path(@conn, :show, u.user) + => link u.user.name, to: ~p"/profiles/#{u.user}" | ( => u.uses ' uses, last used diff --git a/lib/philomena_web/templates/profile/scratchpad/edit.html.slime b/lib/philomena_web/templates/profile/scratchpad/edit.html.slime index bb4ca474..9632e445 100644 --- a/lib/philomena_web/templates/profile/scratchpad/edit.html.slime +++ b/lib/philomena_web/templates/profile/scratchpad/edit.html.slime @@ -1,6 +1,6 @@ h1 Updating Moderation Scratchpad -= form_for @changeset, Routes.profile_scratchpad_path(@conn, :update, @user), [method: "put"], fn f -> += form_for @changeset, ~p"/profiles/#{@user}/scratchpad", [method: "put"], fn f -> = if @changeset.action do .alert.alert-danger p Oops, something went wrong! Please check the errors below. diff --git a/lib/philomena_web/templates/profile/show.html.slime b/lib/philomena_web/templates/profile/show.html.slime index 21eacf74..3179e247 100644 --- a/lib/philomena_web/templates/profile/show.html.slime +++ b/lib/philomena_web/templates/profile/show.html.slime @@ -2,7 +2,7 @@ .profile-top__avatar - avatar = render PhilomenaWeb.UserAttributionView, "_user_avatar.html", object: %{user: @user}, class: "avatar--125px" = if current?(@user, @conn.assigns.current_user) do - = link avatar, to: Routes.avatar_path(@conn, :edit, profile: true), title: "Change avatar" + = link avatar, to: ~p"/avatar/edit?#{[profile: true]}", title: "Change avatar" - else = avatar .profile-top__name-and-links @@ -14,7 +14,7 @@ br = if can?(@conn, :edit_description, @user) do - = link "Edit Personal Title", to: Routes.profile_description_path(@conn, :edit, @user) + = link "Edit Personal Title", to: ~p"/profiles/#{@user}/description/edit" br span @@ -23,21 +23,21 @@ .profile-top__options ul.profile-top__options__column - li = link("Send message", to: Routes.conversation_path(@conn, :new, recipient: @user.name)) - li = link("Our conversations", to: Routes.conversation_path(@conn, :index, with: @user.id)) - li = link("Report this user", to: Routes.profile_report_path(@conn, :new, @user)) + li = link("Send message", to: ~p"/conversations/new?#{[recipient: @user.name]}") + li = link("Our conversations", to: ~p"/conversations?#{[with: @user.id]}") + li = link("Report this user", to: ~p"/profiles/#{@user}/reports/new") ul.profile-top__options__column - li = link("Uploads", to: Routes.search_path(@conn, :index, q: "uploader_id:#{@user.id}")) - li = link("Comments", to: Routes.comment_path(@conn, :index, cq: "user_id:#{@user.id}")) - li = link("Posts", to: Routes.post_path(@conn, :index, pq: "user_id:#{@user.id}")) + li = link("Uploads", to: ~p"/search?#{[q: "uploader_id:#{@user.id}"]}") + li = link("Comments", to: ~p"/comments?#{[cq: "user_id:#{@user.id}"]}") + li = link("Posts", to: ~p"/posts?#{[pq: "user_id:#{@user.id}"]}") = if current?(@user, @conn.assigns.current_user) do - li = link "My reports", to: Routes.report_path(@conn, :index) + li = link "My reports", to: ~p"/reports" ul.profile-top__options__column - li = link("Favorites", to: Routes.search_path(@conn, :index, q: "faved_by_id:#{@user.id}")) - li = link("Tag changes", to: Routes.profile_tag_change_path(@conn, :index, @user)) - li = link("Source changes", to: Routes.profile_source_change_path(@conn, :index, @user)) + li = link("Favorites", to: ~p"/search?#{[q: "faved_by_id:#{@user.id}"]}") + li = link("Tag changes", to: ~p"/profiles/#{@user}/tag_changes") + li = link("Source changes", to: ~p"/profiles/#{@user}/source_changes") = if can_index_user?(@conn) do .js-staff-action @@ -47,7 +47,7 @@ .block i.fa.fa-fw.fa-filter> strong.comment_deleted> Forced Filter: - = link @forced.name, to: Routes.filter_path(@conn, :show, @forced) + = link @forced.name, to: ~p"/filters/#{@forced}" = if (current?(@user, @conn.assigns.current_user) or can?(@conn, :index, Philomena.Bans.User)) and Enum.any?(@bans) do .block @@ -65,7 +65,7 @@ .block = if current?(@user, @conn.assigns.current_user) or manages_links?(@conn, @user) do - a.block__header--single-item href=Routes.profile_artist_link_path(@conn, :new, @user) Artist Links + a.block__header--single-item href=~p"/profiles/#{@user}/artist_links/new" Artist Links - else .block__header span.block__header__title Artist Links @@ -91,10 +91,10 @@ - else ' Hidden ' • - a href=Routes.profile_artist_link_path(@conn, :edit, @user, link) + a href=~p"/profiles/#{@user}/artist_links/#{link}/edit" ' Edit ' • - a href=Routes.admin_artist_link_reject_path(@conn, :create, link) data-method="post" + a href=~p"/admin/artist_links/#{link}/reject" data-method="post" ' Reject - else => unless link.public do @@ -103,7 +103,7 @@ .block = if manages_awards?(@conn) and not hide_staff_tools?(@conn) do - a.block__header--single-item href=Routes.profile_award_path(@conn, :new, @user) Badges + a.block__header--single-item href=~p"/profiles/#{@user}/awards/new" Badges - else .block__header span.block__header__title Badges @@ -120,16 +120,16 @@ = if manages_awards?(@conn) do .flex__grow.center - a href=Routes.profile_award_path(@conn, :delete, @user, award) data-method="delete" data-confirm="Are you really, really sure?" + a href=~p"/profiles/#{@user}/awards/#{award}" data-method="delete" data-confirm="Are you really, really sure?" ' Remove br - a href=Routes.profile_award_path(@conn, :edit, @user, award) + a href=~p"/profiles/#{@user}/awards/#{award}/edit" ' Edit .block .block__header = if can?(@conn, :edit_description, @user) do - a.block__header--single-item href=Routes.profile_description_path(@conn, :edit, @user) About Me + a.block__header--single-item href=~p"/profiles/#{@user}/description/edit" About Me - else span.block__header__title About Me @@ -137,7 +137,7 @@ = if can_read_mod_notes?(@conn) and not hide_staff_tools?(@conn) do .block - a.block__header--single-item href=Routes.profile_detail_path(@conn, :index, @user) Mod Notes + a.block__header--single-item href=~p"/profiles/#{@user}/details" Mod Notes table.table thead tr @@ -150,15 +150,15 @@ td = pretty_time(mod_note.created_at) = if can_index_user?(@conn) do .block - a.block__header--single-item href=Routes.profile_scratchpad_path(@conn, :edit, @user) Moderation Scratchpad + a.block__header--single-item href=~p"/profiles/#{@user}/scratchpad/edit" Moderation Scratchpad .block__content.profile-about = @scratchpad .column-layout__main = render PhilomenaWeb.ProfileView, "_statistics.html", user: @user, statistics: @statistics, conn: @conn - = render PhilomenaWeb.ProfileView, "_recent_images.html", title: "Recent Artwork", images: @recent_artwork, view_all_path: Routes.search_path(@conn, :index, q: tag_disjunction(@tags)), conn: @conn - = render PhilomenaWeb.ProfileView, "_recent_images.html", title: "Recent Uploads", images: @recent_uploads, view_all_path: Routes.search_path(@conn, :index, q: "uploader_id:#{@user.id}"), conn: @conn - = render PhilomenaWeb.ProfileView, "_recent_images.html", title: "Recent Favorites", images: @recent_faves, view_all_path: Routes.search_path(@conn, :index, q: "faved_by_id:#{@user.id}"), conn: @conn + = render PhilomenaWeb.ProfileView, "_recent_images.html", title: "Recent Artwork", images: @recent_artwork, view_all_path: ~p"/search?#{[q: tag_disjunction(@tags)]}", conn: @conn + = render PhilomenaWeb.ProfileView, "_recent_images.html", title: "Recent Uploads", images: @recent_uploads, view_all_path: ~p"/search?#{[q: "uploader_id:#{@user.id}"]}", conn: @conn + = render PhilomenaWeb.ProfileView, "_recent_images.html", title: "Recent Favorites", images: @recent_faves, view_all_path: ~p"/search?#{[q: "faved_by_id:#{@user.id}"]}", conn: @conn = render PhilomenaWeb.ProfileView, "_recent_galleries.html", galleries: @recent_galleries, user: @user, conn: @conn = render PhilomenaWeb.ProfileView, "_recent_comments.html", comments: @recent_comments, user: @user, conn: @conn = render PhilomenaWeb.ProfileView, "_recent_posts.html", posts: @recent_posts, user: @user, conn: @conn diff --git a/lib/philomena_web/templates/profile/source_change/index.html.slime b/lib/philomena_web/templates/profile/source_change/index.html.slime index 906a2820..d03fb4f5 100644 --- a/lib/philomena_web/templates/profile/source_change/index.html.slime +++ b/lib/philomena_web/templates/profile/source_change/index.html.slime @@ -1,9 +1,9 @@ h1 ' Source changes by - a href=Routes.profile_path(@conn, :show, @user) + a href=~p"/profiles/#{@user}" = @user.name -- route = fn p -> Routes.profile_source_change_path(@conn, :index, @user, p) end +- route = fn p -> ~p"/profiles/#{@user}/source_changes?#{p}" end - pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @source_changes, route: route, conn: @conn = render PhilomenaWeb.SourceChangeView, "index.html", conn: @conn, source_changes: @source_changes, pagination: pagination \ No newline at end of file diff --git a/lib/philomena_web/templates/profile/tag_change/index.html.slime b/lib/philomena_web/templates/profile/tag_change/index.html.slime index 806d843a..0cbc97dd 100644 --- a/lib/philomena_web/templates/profile/tag_change/index.html.slime +++ b/lib/philomena_web/templates/profile/tag_change/index.html.slime @@ -1,20 +1,20 @@ h1 ' Tag changes by - a href=Routes.profile_path(@conn, :show, @user) + a href=~p"/profiles/#{@user}" = @user.name -- route = fn p -> Routes.profile_tag_change_path(@conn, :index, @user, p) end +- route = fn p -> ~p"/profiles/#{@user}/tag_changes?#{p}" end - pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @tag_changes, route: route, conn: @conn, params: @pagination_params .block .block__header - = form_for @conn, Routes.profile_tag_change_path(@conn, :index, @user), [method: "get", enforce_utf8: false], fn f -> + = form_for @conn, ~p"/profiles/#{@user}/tag_changes", [method: "get", enforce_utf8: false], fn f -> = text_input f, :only_tag, class: "input", placeholder: "Tag", title: "Only show this tag", autocapitalize: "none" = submit "Search", class: "button", title: "Search" - = link "Removed", to: Routes.profile_tag_change_path(@conn, :index, @user, Keyword.merge(@pagination_params, added: 0)) - = link "Added", to: Routes.profile_tag_change_path(@conn, :index, @user, Keyword.merge(@pagination_params, added: 1)) - = link "All", to: Routes.profile_tag_change_path(@conn, :index, @user, Keyword.delete(@pagination_params, :added)) + = link "Removed", to: ~p"/profiles/#{@user}/tag_changes?#{Keyword.merge(@pagination_params, added: 0)}" + = link "Added", to: ~p"/profiles/#{@user}/tag_changes?#{Keyword.merge(@pagination_params, added: 1)}" + = link "All", to: ~p"/profiles/#{@user}/tag_changes?#{Keyword.delete(@pagination_params, :added)}" .block__header.block__header--light span.block__header__title.page__info diff --git a/lib/philomena_web/templates/registration/edit.html.slime b/lib/philomena_web/templates/registration/edit.html.slime index 88bfd1aa..a0134b6e 100644 --- a/lib/philomena_web/templates/registration/edit.html.slime +++ b/lib/philomena_web/templates/registration/edit.html.slime @@ -6,16 +6,16 @@ p p ' Looking for two factor authentication? - = link "Click here!", to: Routes.registration_totp_path(@conn, :edit) + = link "Click here!", to: ~p"/registrations/totp/edit" p ' Looking to change your avatar? - = link "Click here!", to: Routes.avatar_path(@conn, :edit) + = link "Click here!", to: ~p"/avatar/edit" = if can?(@conn, :change_username, @current_user) do p ' Looking to change your username? - = link "Click here!", to: Routes.registration_name_path(@conn, :edit) + = link "Click here!", to: ~p"/registrations/name/edit" h3 API Key p @@ -33,7 +33,7 @@ p h3 Change email -= form_for @email_changeset, Routes.registration_email_path(@conn, :create), [method: :post], fn f -> += form_for @email_changeset, ~p"/registrations/email", [method: :post], fn f -> = if @email_changeset.action do .alert.alert-danger p Oops, something went wrong! Please check the errors below. @@ -51,7 +51,7 @@ h3 Change email h3 Change password -= form_for @password_changeset, Routes.registration_password_path(@conn, :update), fn f -> += form_for @password_changeset, ~p"/registrations/password", fn f -> = if @password_changeset.action do .alert.alert-danger p Oops, something went wrong! Please check the errors below. diff --git a/lib/philomena_web/templates/registration/name/edit.html.slime b/lib/philomena_web/templates/registration/name/edit.html.slime index 529b57a1..1f9bce28 100644 --- a/lib/philomena_web/templates/registration/name/edit.html.slime +++ b/lib/philomena_web/templates/registration/name/edit.html.slime @@ -1,6 +1,6 @@ h1 Editing Name -= form_for @changeset, Routes.registration_name_path(@conn, :update), [as: :user], fn f -> += form_for @changeset, ~p"/registrations/name", [as: :user], fn f -> = if @changeset.action do .alert.alert-danger p Oops, something went wrong! Please check the errors below. @@ -14,4 +14,4 @@ h1 Editing Name .action = submit "Save", class: "button" -p = link "Back", to: Routes.registration_path(@conn, :edit) +p = link "Back", to: ~p"/registrations/edit" diff --git a/lib/philomena_web/templates/registration/new.html.slime b/lib/philomena_web/templates/registration/new.html.slime index 99e49ab6..82d8b8d5 100644 --- a/lib/philomena_web/templates/registration/new.html.slime +++ b/lib/philomena_web/templates/registration/new.html.slime @@ -1,6 +1,6 @@ h1 Register -= form_for @changeset, Routes.registration_path(@conn, :create), fn f -> += form_for @changeset, ~p"/registrations", fn f -> = if @changeset.action do .alert.alert-danger p Oops, something went wrong! Please check the errors below. diff --git a/lib/philomena_web/templates/registration/totp/edit.html.slime b/lib/philomena_web/templates/registration/totp/edit.html.slime index 9c95f2f8..8fd3028b 100644 --- a/lib/philomena_web/templates/registration/totp/edit.html.slime +++ b/lib/philomena_web/templates/registration/totp/edit.html.slime @@ -1,6 +1,6 @@ h1 Two Factor Authentication -= form_for @changeset, Routes.registration_totp_path(@conn, :update), [as: :user], fn f -> += form_for @changeset, ~p"/registrations/totp", [as: :user], fn f -> = if @changeset.action do .alert.alert-danger p Oops, something went wrong! Please check the errors below. @@ -133,4 +133,4 @@ h1 Two Factor Authentication = submit "Save Account", class: "button" -p = link "Back", to: Routes.registration_path(@conn, :edit) +p = link "Back", to: ~p"/registrations/edit" diff --git a/lib/philomena_web/templates/report/index.html.slime b/lib/philomena_web/templates/report/index.html.slime index 48bb98b8..a7e35224 100644 --- a/lib/philomena_web/templates/report/index.html.slime +++ b/lib/philomena_web/templates/report/index.html.slime @@ -2,7 +2,7 @@ h1 Your Reports .block .block__header span.block__header__title Reports - - route = fn p -> Routes.report_path(@conn, :index, p) end + - route = fn p -> ~p"/reports?#{p}" end = render PhilomenaWeb.PaginationView, "_pagination.html", page: @reports, route: route, conn: @conn .block__content diff --git a/lib/philomena_web/templates/search/_form.html.slime b/lib/philomena_web/templates/search/_form.html.slime index d5b52422..efc065af 100644 --- a/lib/philomena_web/templates/search/_form.html.slime +++ b/lib/philomena_web/templates/search/_form.html.slime @@ -1,6 +1,6 @@ h1 Search -= form_for :search, Routes.search_path(@conn, :index), [id: "searchform", method: "get", class: "js-search-form", enforce_utf8: false], fn f -> += form_for :search, ~p"/search", [id: "searchform", method: "get", class: "js-search-form", enforce_utf8: false], fn f -> = text_input f, :q, class: "input input--wide js-search-field", placeholder: "Search terms are chained with commas", autocapitalize: "none", name: "q", value: @conn.params["q"] .block diff --git a/lib/philomena_web/templates/search/index.html.slime b/lib/philomena_web/templates/search/index.html.slime index 2c4cffe9..130d7dd4 100644 --- a/lib/philomena_web/templates/search/index.html.slime +++ b/lib/philomena_web/templates/search/index.html.slime @@ -1,6 +1,6 @@ = cond do - Enum.any?(@images) or override_display(@tags) -> - = render PhilomenaWeb.ImageView, "index.html", conn: @conn, tags: @tags, images: @images, header: "Searching for #{@conn.params["q"]}", route: fn p -> Routes.search_path(@conn, :index, p) end, scope: scope(@conn) + = render PhilomenaWeb.ImageView, "index.html", conn: @conn, tags: @tags, images: @images, header: "Searching for #{@conn.params["q"]}", route: fn p -> ~p"/search?#{p}" end, scope: scope(@conn) - assigns[:error] -> .block.block--fixed.block--danger diff --git a/lib/philomena_web/templates/search/reverse/index.html.slime b/lib/philomena_web/templates/search/reverse/index.html.slime index a4c24e01..876be913 100644 --- a/lib/philomena_web/templates/search/reverse/index.html.slime +++ b/lib/philomena_web/templates/search/reverse/index.html.slime @@ -1,6 +1,6 @@ h1 Reverse Search -= form_for :image, Routes.search_reverse_path(@conn, :create), [multipart: true], fn f -> += form_for :image, ~p"/search/reverse", [multipart: true], fn f -> p ' Basic image similarity search. Finds uploaded images similar to the one ' provided based on simple intensities and uses the median frame of @@ -46,7 +46,7 @@ h1 Reverse Search = for match <- @images do tr th - h3 = link "##{match.id}", to: Routes.image_path(@conn, :show, match) + h3 = link "##{match.id}", to: ~p"/images/#{match}" p = if image_has_sources(match) do span.source_url diff --git a/lib/philomena_web/templates/session/new.html.slime b/lib/philomena_web/templates/session/new.html.slime index 112ebaae..3d856c2d 100644 --- a/lib/philomena_web/templates/session/new.html.slime +++ b/lib/philomena_web/templates/session/new.html.slime @@ -1,13 +1,13 @@ h1 Sign in -= form_for @conn, Routes.session_path(@conn, :create), [as: :user], fn f -> += form_for @conn, ~p"/sessions", [as: :user], fn f -> = if @error_message do .alert.alert-danger p = @error_message - p = link "Resend unlock instructions", to: Routes.unlock_path(@conn, :new) - p = link "Resend confirmation email", to: Routes.confirmation_path(@conn, :new) + p = link "Resend unlock instructions", to: ~p"/unlocks/new" + p = link "Resend confirmation email", to: ~p"/confirmations/new" - p = link "Forgot your password?", to: Routes.password_path(@conn, :new) + p = link "Forgot your password?", to: ~p"/passwords/new" .field = email_input f, :email, class: "input", required: true, placeholder: "Email", autofocus: true, pattern: ~S/[^\s]+@[^\s]+\.[^\s]+/ diff --git a/lib/philomena_web/templates/session/totp/new.html.slime b/lib/philomena_web/templates/session/totp/new.html.slime index 0c3bf9eb..0a632f9f 100644 --- a/lib/philomena_web/templates/session/totp/new.html.slime +++ b/lib/philomena_web/templates/session/totp/new.html.slime @@ -1,6 +1,6 @@ h1 Two Factor Authentication -= form_for @changeset, Routes.session_totp_path(@conn, :create), [as: :user, method: "post"], fn f -> += form_for @changeset, ~p"/sessions/totp", [as: :user, method: "post"], fn f -> .field h4 Please enter your 2FA code = text_input f, :twofactor_token, class: "input", placeholder: "6-digit code", required: true, autofocus: true, autocomplete: "off" diff --git a/lib/philomena_web/templates/setting/edit.html.slime b/lib/philomena_web/templates/setting/edit.html.slime index 2809de42..a2185cc0 100644 --- a/lib/philomena_web/templates/setting/edit.html.slime +++ b/lib/philomena_web/templates/setting/edit.html.slime @@ -1,5 +1,5 @@ h1 Content Settings -= form_for @changeset, Routes.setting_path(@conn, :update), [method: "put"], fn f -> += form_for @changeset, ~p"/settings", [method: "put"], fn f -> = if @changeset.action do .alert.alert-danger p Oops, something went wrong! Please check the errors below. @@ -51,7 +51,7 @@ h1 Content Settings code> = link("Click to show", to: "#", data: [click_show: "#rss-link", click_hide: "#rss-feed-button"]) #rss-link.hidden - = url_input f, :subscribe_url, value: Routes.api_rss_watched_url(@conn, :index, key: @conn.assigns.current_user.authentication_token), class: "input input--wide" + = url_input f, :subscribe_url, value: url(~p"/api/v1/rss/watched?#{[key: @conn.assigns.current_user.authentication_token]}"), class: "input input--wide" br ' Do not share this URL with anyone, it may allow an attacker to compromise your account. @@ -184,7 +184,7 @@ h1 Content Settings .block__tab.hidden data-tab="join-the-herd" p ' Consider - => link "creating an account!", to: Routes.registration_path(@conn, :new) + => link "creating an account!", to: ~p"/registrations/new" br ' You will be able to customize the number of images and comments you get on a single page, as well as change the appearance of the site with custom themes. diff --git a/lib/philomena_web/templates/source_change/index.html.slime b/lib/philomena_web/templates/source_change/index.html.slime index 05971a76..fe4b37b2 100644 --- a/lib/philomena_web/templates/source_change/index.html.slime +++ b/lib/philomena_web/templates/source_change/index.html.slime @@ -16,7 +16,7 @@ = for source_change <- @source_changes do tr td.center - = link source_change.image_id, to: Routes.image_path(@conn, :show, source_change.image) + = link source_change.image_id, to: ~p"/images/#{source_change.image}" td.center = render PhilomenaWeb.ImageView, "_image_container.html", image: source_change.image, size: :thumb_tiny, conn: @conn diff --git a/lib/philomena_web/templates/staff/index.html.slime b/lib/philomena_web/templates/staff/index.html.slime index 64e43a2a..c8373b59 100644 --- a/lib/philomena_web/templates/staff/index.html.slime +++ b/lib/philomena_web/templates/staff/index.html.slime @@ -37,12 +37,12 @@ h1 Staff .block__content.staff-block__user .staff-block__user-card .staff-block__avatar - a.profile-block href=Routes.profile_path(@conn, :show, user) + a.profile-block href=~p"/profiles/#{user}" = render PhilomenaWeb.UserAttributionView, "_user_avatar.html", object: %{user: user}, class: "avatar--125px" p b = user.name .staff-block__info - = link to: Routes.conversation_path(@conn, :new, recipient: user.name), class: "button" do + = link to: ~p"/conversations/new?#{[recipient: user.name]}", class: "button" do i.fa.fa-envelope> ' Send PM hr.staff-block__separator diff --git a/lib/philomena_web/templates/tag/_tag.html.slime b/lib/philomena_web/templates/tag/_tag.html.slime index 4bc77882..0de59b7e 100644 --- a/lib/philomena_web/templates/tag/_tag.html.slime +++ b/lib/philomena_web/templates/tag/_tag.html.slime @@ -13,14 +13,14 @@ span.tag.dropdown data-tag-category="#{@tag.category}" data-tag-id="#{@tag.id}" a.tag__name< href=pretty_tag_path(@tag) title="#{@tag.short_description}" = @tag.name div.dropdown__content - a.tag__dropdown__link.hidden data-method="delete" data-remote="true" data-tag-action="unwatch" href=Routes.tag_watch_path(@conn, :delete, @tag) Unwatch - a.tag__dropdown__link.hidden data-method="post" data-remote="true" data-tag-action="watch" href=Routes.tag_watch_path(@conn, :create, @tag) Watch + a.tag__dropdown__link.hidden data-method="delete" data-remote="true" data-tag-action="unwatch" href=~p"/tags/#{@tag}/watch" Unwatch + a.tag__dropdown__link.hidden data-method="post" data-remote="true" data-tag-action="watch" href=~p"/tags/#{@tag}/watch" Watch - a.tag__dropdown__link.hidden data-method="delete" data-remote="true" data-tag-action="unspoiler" href=Routes.filter_spoiler_path(@conn, :delete, tag: @tag) Unspoiler - a.tag__dropdown__link.hidden data-method="post" data-remote="true" data-tag-action="spoiler" href=Routes.filter_spoiler_path(@conn, :create, tag: @tag) Spoiler + a.tag__dropdown__link.hidden data-method="delete" data-remote="true" data-tag-action="unspoiler" href=~p"/filters/spoiler?#{[tag: @tag]}" Unspoiler + a.tag__dropdown__link.hidden data-method="post" data-remote="true" data-tag-action="spoiler" href=~p"/filters/spoiler?#{[tag: @tag]}" Spoiler - a.tag__dropdown__link.hidden data-method="delete" data-remote="true" data-tag-action="unhide" href=Routes.filter_hide_path(@conn, :delete, tag: @tag) Unhide - a.tag__dropdown__link.hidden data-method="post" data-remote="true" data-tag-action="hide" href=Routes.filter_hide_path(@conn, :create, tag: @tag) Hide + a.tag__dropdown__link.hidden data-method="delete" data-remote="true" data-tag-action="unhide" href=~p"/filters/hide?#{[tag: @tag]}" Unhide + a.tag__dropdown__link.hidden data-method="post" data-remote="true" data-tag-action="hide" href=~p"/filters/hide?#{[tag: @tag]}" Hide a.tag__dropdown__link.hidden href="/sessions/new" Sign in to Watch a.tag__dropdown__link.hidden href="/filters" Filter diff --git a/lib/philomena_web/templates/tag/_tag_info_row.html.slime b/lib/philomena_web/templates/tag/_tag_info_row.html.slime index 5e38db97..2bd36b42 100644 --- a/lib/philomena_web/templates/tag/_tag_info_row.html.slime +++ b/lib/philomena_web/templates/tag/_tag_info_row.html.slime @@ -7,12 +7,12 @@ .flex__grow = render PhilomenaWeb.TagView, "_tag.html", tag: @tag, conn: @conn - = link "Tag changes", to: Routes.tag_tag_change_path(@conn, :index, @tag), class: "detail-link" + = link "Tag changes", to: ~p"/tags/#{@tag}/tag_changes", class: "detail-link" = if manages_tags?(@conn) do - = link "Edit details", to: Routes.tag_path(@conn, :edit, @tag), class: "detail-link" - = link "Usage", to: Routes.tag_detail_path(@conn, :index, @tag), class: "detail-link" + = link "Edit details", to: ~p"/tags/#{@tag}/edit", class: "detail-link" + = link "Usage", to: ~p"/tags/#{@tag}/details", class: "detail-link" = if manages_dnp?(@conn) do - = link "Create new DNP entry", to: Routes.dnp_entry_path(@conn, :new, tag_id: @tag.id), class: "detail-link" + = link "Create new DNP entry", to: ~p"/dnp/new?#{[tag_id: @tag.id]}", class: "detail-link" br @@ -29,14 +29,14 @@ = if Enum.any?(@tag.aliases) do strong> Aliases: = if aliases_tags?(@conn) do - = map_join(@tag.aliases, ", ", &link(&1.name, to: Routes.tag_alias_path(@conn, :edit, &1))) + = map_join(@tag.aliases, ", ", &link(&1.name, to: ~p"/tags/#{&1}/alias/edit")) - else = map_join(@tag.aliases, ", ", & &1.name) br = if Enum.any?(@tag.implied_tags) do strong> Implies: - = map_join(@tag.implied_tags, ", ", &link(&1.name, to: Routes.tag_path(@conn, :show, &1))) + = map_join(@tag.implied_tags, ", ", &link(&1.name, to: ~p"/tags/#{&1}")) br = if Enum.any?(@tag.hidden_links) and manages_links?(@conn) do @@ -44,7 +44,7 @@ br = for artist_link <- @tag.hidden_links do - => link artist_link.user.name, to: Routes.profile_path(@conn, :show, artist_link.user) + => link artist_link.user.name, to: ~p"/profiles/#{artist_link.user}" ' → => link artist_link.uri, to: artist_link.uri br @@ -70,18 +70,18 @@ - users = Enum.map(@tag.public_links, & &1.user) |> Enum.uniq_by(& &1.id) = for user <- users do - => link user.name, to: Routes.profile_path(@conn, :show, user) + => link user.name, to: ~p"/profiles/#{user}" br = if Enum.any?(@tag.channels) do strong> Associated streams: = for channel <- @tag.channels do - => link channel.title, to: Routes.channel_path(@conn, :show, channel) + => link channel.title, to: ~p"/channels/#{channel}" = if can?(@conn, :edit, channel) do | ( - = link "Edit", to: Routes.channel_path(@conn, :edit, channel) + = link "Edit", to: ~p"/channels/#{channel}/edit" ' ) br @@ -94,7 +94,7 @@ .toggle-box-container .toggle-box-container__content = map_join @tag.implied_by_tags, ", ", fn tag -> - = link tag.name, to: Routes.tag_path(@conn, :show, tag) + = link tag.name, to: ~p"/tags/#{tag}" br @@ -117,5 +117,5 @@ => body | ( - = link "more info", to: Routes.dnp_entry_path(@conn, :show, entry) + = link "more info", to: ~p"/dnp/#{entry}" | ) diff --git a/lib/philomena_web/templates/tag/alias/edit.html.slime b/lib/philomena_web/templates/tag/alias/edit.html.slime index 706545bc..346aae09 100644 --- a/lib/philomena_web/templates/tag/alias/edit.html.slime +++ b/lib/philomena_web/templates/tag/alias/edit.html.slime @@ -2,7 +2,7 @@ h1 ' Aliasing tag = @tag.name -= form_for @changeset, Routes.tag_alias_path(@conn, :update, @tag), [method: "put"], fn f -> += form_for @changeset, ~p"/tags/#{@tag}/alias", [method: "put"], fn f -> = if @changeset.action do .alert.alert-danger p Oops, something went wrong! Please check the errors below. @@ -17,7 +17,7 @@ h1 => submit "Alias tag", class: "button" br -= button_to "Remove tag alias", Routes.tag_alias_path(@conn, :delete, @tag), method: "delete", class: "button", data: [confirm: "Are you really, really sure?", disable_with: raw("Saving…")] += button_to "Remove tag alias", ~p"/tags/#{@tag}/alias", method: "delete", class: "button", data: [confirm: "Are you really, really sure?", disable_with: raw("Saving…")] br -= link "Back", to: Routes.tag_path(@conn, :show, @tag) += link "Back", to: ~p"/tags/#{@tag}" diff --git a/lib/philomena_web/templates/tag/detail/_filters.html.slime b/lib/philomena_web/templates/tag/detail/_filters.html.slime index b09071a8..8dfdb621 100644 --- a/lib/philomena_web/templates/tag/detail/_filters.html.slime +++ b/lib/philomena_web/templates/tag/detail/_filters.html.slime @@ -9,7 +9,7 @@ table.table tbody = for filter <- @filters do tr - td = link filter.name, to: Routes.filter_path(@conn, :show, filter) + td = link filter.name, to: ~p"/filters/#{filter}" td = cond do - filter.system -> @@ -23,7 +23,7 @@ table.table td = if filter.user do - = link filter.user.name, to: Routes.profile_path(@conn, :show, filter.user) + = link filter.user.name, to: ~p"/profiles/#{filter.user}" - else ' No user associated diff --git a/lib/philomena_web/templates/tag/detail/index.html.slime b/lib/philomena_web/templates/tag/detail/index.html.slime index 8a11358a..5271cab2 100644 --- a/lib/philomena_web/templates/tag/detail/index.html.slime +++ b/lib/philomena_web/templates/tag/detail/index.html.slime @@ -1,6 +1,6 @@ h1 ' Tag Usage for - = link @tag.name, to: Routes.tag_path(@conn, :show, @tag) + = link @tag.name, to: ~p"/tags/#{@tag}" h3 Filters that spoiler this tag: = render PhilomenaWeb.Tag.DetailView, "_filters.html", filters: @filters_spoilering, conn: @conn @@ -14,4 +14,4 @@ h3 | ) = for u <- @users_watching do - = link u.name, to: Routes.profile_path(@conn, :show, u), class: "interaction-user-list-item" + = link u.name, to: ~p"/profiles/#{u}", class: "interaction-user-list-item" diff --git a/lib/philomena_web/templates/tag/edit.html.slime b/lib/philomena_web/templates/tag/edit.html.slime index ee2a6d4d..f5faedb7 100644 --- a/lib/philomena_web/templates/tag/edit.html.slime +++ b/lib/philomena_web/templates/tag/edit.html.slime @@ -1,10 +1,10 @@ h1 Editing Tag -p = link "Edit image", to: Routes.tag_image_path(@conn, :edit, @tag) +p = link "Edit image", to: ~p"/tags/#{@tag}/image/edit" = if can?(@conn, :alias, @tag) do - p = link "Edit aliases", to: Routes.tag_alias_path(@conn, :edit, @tag) + p = link "Edit aliases", to: ~p"/tags/#{@tag}/alias/edit" -= form_for @changeset, Routes.tag_path(@conn, :update, @tag), [class: "form"], fn f -> += form_for @changeset, ~p"/tags/#{@tag}", [class: "form"], fn f -> = if @changeset.action do .alert.alert-danger p Oops, something went wrong! Please check the errors below. @@ -44,10 +44,10 @@ br label for="tag-management" Tag Processing .toggle-box-container .toggle-box-container__content - = button_to "Rebuild index", Routes.tag_reindex_path(@conn, :create, @tag), method: "post", class: "button", data: [confirm: "Are you really, really sure?", disable_with: raw("Reindexing…")] + = button_to "Rebuild index", ~p"/tags/#{@tag}/reindex", method: "post", class: "button", data: [confirm: "Are you really, really sure?", disable_with: raw("Reindexing…")] p Use this if the tag displays the wrong number of images or returns the wrong search results. - = button_to "Destroy tag", Routes.tag_path(@conn, :delete, @tag), method: "delete", class: "button button--state-danger", data: [confirm: "Are you really, really sure?", disable_with: raw("Deleting…")] + = button_to "Destroy tag", ~p"/tags/#{@tag}", method: "delete", class: "button button--state-danger", data: [confirm: "Are you really, really sure?", disable_with: raw("Deleting…")] p strong Irreversible. Use with extreme caution! ul diff --git a/lib/philomena_web/templates/tag/image/edit.html.slime b/lib/philomena_web/templates/tag/image/edit.html.slime index c452561f..778a9b87 100644 --- a/lib/philomena_web/templates/tag/image/edit.html.slime +++ b/lib/philomena_web/templates/tag/image/edit.html.slime @@ -15,7 +15,7 @@ p Add a new image or remove the existing one here. p SVG is preferred. - = form_for @changeset, Routes.tag_image_path(@conn, :update, @tag), [method: "put", multipart: true], fn f -> + = form_for @changeset, ~p"/tags/#{@tag}/image", [method: "put", multipart: true], fn f -> = if @changeset.action do .alert.alert-danger p Oops, something went wrong! Please check the errors below. @@ -35,7 +35,7 @@ => submit "Update tag image", class: "button" br - = button_to "Remove tag image", Routes.tag_image_path(@conn, :delete, @tag), method: "delete", class: "button", data: [confirm: "Are you really, really sure?"] + = button_to "Remove tag image", ~p"/tags/#{@tag}/image", method: "delete", class: "button", data: [confirm: "Are you really, really sure?"] br - = link "Back", to: Routes.tag_path(@conn, :show, @tag) + = link "Back", to: ~p"/tags/#{@tag}" diff --git a/lib/philomena_web/templates/tag/index.html.slime b/lib/philomena_web/templates/tag/index.html.slime index 605dfa9b..89931cea 100644 --- a/lib/philomena_web/templates/tag/index.html.slime +++ b/lib/philomena_web/templates/tag/index.html.slime @@ -1,6 +1,6 @@ h1 Tags -= form_for :tags, Routes.tag_path(@conn, :index), [method: "get", class: "hform", enforce_utf8: false], fn f -> += form_for :tags, ~p"/tags", [method: "get", class: "hform", enforce_utf8: false], fn f -> .field = text_input f, :tq, name: :tq, value: @conn.params["tq"] || "*", class: "input hform__text", placeholder: "Search tags", autocapitalize: "none" = submit "Search", class: "hform__button button" @@ -15,7 +15,7 @@ h2 Search Results = cond do - Enum.any?(@tags) -> - - route = fn p -> Routes.tag_path(@conn, :index, p) end + - route = fn p -> ~p"/tags?#{p}" end - pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @tags, route: route, params: [tq: @conn.params["tq"] || "*"] = render PhilomenaWeb.TagView, "_tag_list.html", tags: @tags, conn: @conn @@ -56,102 +56,102 @@ table.table td Literal td Matches the name of the target tag, if this tag is aliased. td - code = link "alias_of:twilight sparkle", to: Routes.tag_path(@conn, :index, tq: "alias_of:twilight sparkle") + code = link "alias_of:twilight sparkle", to: ~p"/tags?#{[tq: "alias_of:twilight sparkle"]}" tr td code aliased td Boolean td Matches when this tag is aliased. td - code = link "aliased:true", to: Routes.tag_path(@conn, :index, tq: "aliased:true") + code = link "aliased:true", to: ~p"/tags?#{[tq: "aliased:true"]}" tr td code aliases td Literal td Matches the name of any of this tag's aliases. td - code = link "aliases:ts", to: Routes.tag_path(@conn, :index, tq: "aliases:ts") + code = link "aliases:ts", to: ~p"/tags?#{[tq: "aliases:ts"]}" tr td code analyzed_name td Full Text td Matches the name of this tag. This is the default field. td - code = link "analyzed_name:wing", to: Routes.tag_path(@conn, :index, tq: "analyzed_name:wing") + code = link "analyzed_name:wing", to: ~p"/tags?#{[tq: "analyzed_name:wing"]}" tr td code category td Literal td Matches the category this tag belongs to. td - code = link "category:origin", to: Routes.tag_path(@conn, :index, tq: "category:origin") + code = link "category:origin", to: ~p"/tags?#{[tq: "category:origin"]}" tr td code description td Full Text td Matches the text of the full description for this tag. td - code = link "description:species", to: Routes.tag_path(@conn, :index, tq: "description:species") + code = link "description:species", to: ~p"/tags?#{[tq: "description:species"]}" tr td code id td Numeric Range td Matches the numeric surrogate key for this tag. td - code = link "id:40482", to: Routes.tag_path(@conn, :index, tq: "id:40482") + code = link "id:40482", to: ~p"/tags?#{[tq: "id:40482"]}" tr td code images td Numeric Range td Matches tags with the specified image count. td - code = link "images.lte:1000", to: Routes.tag_path(@conn, :index, tq: "images.lte:1000") + code = link "images.lte:1000", to: ~p"/tags?#{[tq: "images.lte:1000"]}" tr td code implied_by td Literal td Matches this tag if it is implied by the given tag. td - code = link "implied_by:transparent background", to: Routes.tag_path(@conn, :index, tq: "implied_by:transparent background") + code = link "implied_by:transparent background", to: ~p"/tags?#{[tq: "implied_by:transparent background"]}" tr td code implies td Literal td Matches this tag if it implies the given tag. td - code = link "implies:shipping", to: Routes.tag_path(@conn, :index, tq: "implies:shipping") + code = link "implies:shipping", to: ~p"/tags?#{[tq: "implies:shipping"]}" tr td code name td Literal td Matches the exact name of this tag. td - code = link "name:safe", to: Routes.tag_path(@conn, :index, tq: "name:safe") + code = link "name:safe", to: ~p"/tags?#{[tq: "name:safe"]}" tr td code name_in_namespace td Literal td Matches the name of this tag with any namespace component removed. td - code = link "name_in_namespace:johnjoseco", to: Routes.tag_path(@conn, :index, tq: "name_in_namespace:johnjoseco") + code = link "name_in_namespace:johnjoseco", to: ~p"/tags?#{[tq: "name_in_namespace:johnjoseco"]}" tr td code namespace td Literal td Matches tags with the given namespace. td - code = link "namespace:artist", to: Routes.tag_path(@conn, :index, tq: "namespace:artist") + code = link "namespace:artist", to: ~p"/tags?#{[tq: "namespace:artist"]}" tr td code short_description td Full Text td Matches the text of the short description for this tag. td - code = link "short_description:gender", to: Routes.tag_path(@conn, :index, tq: "short_description:gender") + code = link "short_description:gender", to: ~p"/tags?#{[tq: "short_description:gender"]}" tr td code slug td Literal td Matches the slug of this tag. td - code = link "slug:-fwslash-mlp-fwslash-", to: Routes.tag_path(@conn, :index, tq: "slug:-fwslash-mlp-fwslash-") + code = link "slug:-fwslash-mlp-fwslash-", to: ~p"/tags?#{[tq: "slug:-fwslash-mlp-fwslash-"]}" diff --git a/lib/philomena_web/templates/tag/show.html.slime b/lib/philomena_web/templates/tag/show.html.slime index a8b85c43..ad85fbed 100644 --- a/lib/philomena_web/templates/tag/show.html.slime +++ b/lib/philomena_web/templates/tag/show.html.slime @@ -1,3 +1,3 @@ -= render PhilomenaWeb.ImageView, "index.html", conn: @conn, tags: @tags, images: @images, header: "Images tagged #{@tag.name}", scope: scope(@conn), route: fn p -> Routes.tag_path(@conn, :show, @tag, p) end += render PhilomenaWeb.ImageView, "index.html", conn: @conn, tags: @tags, images: @images, header: "Images tagged #{@tag.name}", scope: scope(@conn), route: fn p -> ~p"/tags/#{@tag}?#{p}" end = render PhilomenaWeb.SearchView, "_form.html", conn: @conn diff --git a/lib/philomena_web/templates/tag/tag_change/index.html.slime b/lib/philomena_web/templates/tag/tag_change/index.html.slime index caf85dbd..a91d1ede 100644 --- a/lib/philomena_web/templates/tag/tag_change/index.html.slime +++ b/lib/philomena_web/templates/tag/tag_change/index.html.slime @@ -1,9 +1,9 @@ h1 ' Tag changes on tag - a href=Routes.tag_path(@conn, :show, @tag) + a href=~p"/tags/#{@tag}" = @tag.name -- route = fn p -> Routes.tag_tag_change_path(@conn, :index, @tag, p) end +- route = fn p -> ~p"/tags/#{@tag}/tag_changes?#{p}" end - params = if @conn.params["added"], do: [added: @conn.params["added"]] - pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @tag_changes, route: route, conn: @conn, params: params @@ -12,8 +12,8 @@ h1 span.block__header__title | Display only: - = link "Removed", to: Routes.tag_tag_change_path(@conn, :index, @tag, added: 0) - = link "Added", to: Routes.tag_tag_change_path(@conn, :index, @tag, added: 1) - = link "All", to: Routes.tag_tag_change_path(@conn, :index, @tag) + = link "Removed", to: ~p"/tags/#{@tag}/tag_changes?#{[added: 0]}" + = link "Added", to: ~p"/tags/#{@tag}/tag_changes?#{[added: 1]}" + = link "All", to: ~p"/tags/#{@tag}/tag_changes" = render PhilomenaWeb.TagChangeView, "index.html", conn: @conn, tag_changes: @tag_changes, pagination: pagination diff --git a/lib/philomena_web/templates/tag_change/index.html.slime b/lib/philomena_web/templates/tag_change/index.html.slime index a5f6b64b..cfffd345 100644 --- a/lib/philomena_web/templates/tag_change/index.html.slime +++ b/lib/philomena_web/templates/tag_change/index.html.slime @@ -7,7 +7,7 @@ i.fa.fa-check> ' Toggle all -= form_for :tag_changes, Routes.tag_change_revert_path(@conn, :create), [class: "tag-changes-form"], fn _f -> += form_for :tag_changes, ~p"/tag_changes/revert", [class: "tag-changes-form"], fn _f -> .block__content table.table thead @@ -31,7 +31,7 @@ input type="checkbox" name="ids[]" value=tag_change.id td.center - = link tag_change.image_id, to: Routes.image_path(@conn, :show, tag_change.image) + = link tag_change.image_id, to: ~p"/images/#{tag_change.image}" td.center = render PhilomenaWeb.ImageView, "_image_container.html", image: tag_change.image, size: :thumb_tiny, conn: @conn @@ -69,7 +69,7 @@ td.danger No = if reverts_tag_changes?(@conn) do td - a href=Routes.image_tag_change_path(@conn, :delete, tag_change.image, tag_change) data-method="delete" data-confirm="Are you really, really sure?" + a href=~p"/images/#{tag_change.image}/tag_changes/#{tag_change}" data-method="delete" data-confirm="Are you really, really sure?" ' Delete from history .block__header diff --git a/lib/philomena_web/templates/topic/new.html.slime b/lib/philomena_web/templates/topic/new.html.slime index 5d42d130..05236f7a 100644 --- a/lib/philomena_web/templates/topic/new.html.slime +++ b/lib/philomena_web/templates/topic/new.html.slime @@ -1,4 +1,4 @@ -= form_for @changeset, Routes.forum_topic_path(@conn, :create, @forum), fn f -> += form_for @changeset, ~p"/forums/#{@forum}/topics", fn f -> = if @changeset.action do .alert.alert-danger p Oops, something went wrong! Please check the errors below. diff --git a/lib/philomena_web/templates/topic/poll/_display.html.slime b/lib/philomena_web/templates/topic/poll/_display.html.slime index eb253fbc..780b6336 100644 --- a/lib/philomena_web/templates/topic/poll/_display.html.slime +++ b/lib/philomena_web/templates/topic/poll/_display.html.slime @@ -2,7 +2,7 @@ = link "Voting", to: "#", class: "selected", data: [click_tab: "voting"] = if can?(@conn, :hide, @topic) do - = link "Voters", to: "#", data: [click_tab: "voters", load_tab: Routes.forum_topic_poll_vote_path(@conn, :index, @forum, @topic)] + = link "Voters", to: "#", data: [click_tab: "voters", load_tab: ~p"/forums/#{@forum}/topics/#{@topic}/poll/votes"] = link "Administrate", to: "#", data: [click_tab: "administration"] .block__tab data-tab="voting" @@ -31,6 +31,6 @@ .block__tab.hidden data-tab="voters" p Loading… .block__tab.hidden data-tab="administration" - a.button.button--state-warning.js-staff-action> href=Routes.forum_topic_poll_path(@conn, :edit, @forum, @topic) + a.button.button--state-warning.js-staff-action> href=~p"/forums/#{@forum}/topics/#{@topic}/poll/edit" i.fa.fa-edit> | Edit diff --git a/lib/philomena_web/templates/topic/poll/_vote_form.html.slime b/lib/philomena_web/templates/topic/poll/_vote_form.html.slime index be90c184..08f209ff 100644 --- a/lib/philomena_web/templates/topic/poll/_vote_form.html.slime +++ b/lib/philomena_web/templates/topic/poll/_vote_form.html.slime @@ -1,4 +1,4 @@ -= form_for :poll_vote, Routes.forum_topic_poll_vote_path(@conn, :create, @forum, @topic), [class: "poll-vote-form"], fn _f -> += form_for :poll_vote, ~p"/forums/#{@forum}/topics/#{@topic}/poll/votes", [class: "poll-vote-form"], fn _f -> h4.poll__header ' Poll: = @poll.title diff --git a/lib/philomena_web/templates/topic/poll/edit.html.slime b/lib/philomena_web/templates/topic/poll/edit.html.slime index 1282a99e..03cf0640 100644 --- a/lib/philomena_web/templates/topic/poll/edit.html.slime +++ b/lib/philomena_web/templates/topic/poll/edit.html.slime @@ -1,6 +1,6 @@ h1 Editing Poll -= form_for @changeset, Routes.forum_topic_poll_path(@conn, :update, @forum, @topic), fn f -> += form_for @changeset, ~p"/forums/#{@forum}/topics/#{@topic}/poll", fn f -> = render PhilomenaWeb.Topic.PollView, "_form.html", f: f br diff --git a/lib/philomena_web/templates/topic/poll/vote/index.html.slime b/lib/philomena_web/templates/topic/poll/vote/index.html.slime index 5b71a100..749d9cb3 100644 --- a/lib/philomena_web/templates/topic/poll/vote/index.html.slime +++ b/lib/philomena_web/templates/topic/poll/vote/index.html.slime @@ -4,8 +4,8 @@ = for vote <- option.poll_votes do span.interaction-user-list-item - => link vote.user.name, to: Routes.profile_path(@conn, :show, vote.user) - /= link "(x)", to: Routes.forum_topic_poll_vote_path(@conn, :delete, @forum, @topic, vote) + => link vote.user.name, to: ~p"/profiles/#{vote.user}" + /= link "(x)", to: ~p"/forums/#{@forum}/topics/#{@topic}/poll/votes/#{vote}" - else p diff --git a/lib/philomena_web/templates/topic/post/_form.html.slime b/lib/philomena_web/templates/topic/post/_form.html.slime index aa69b979..dcb15f40 100644 --- a/lib/philomena_web/templates/topic/post/_form.html.slime +++ b/lib/philomena_web/templates/topic/post/_form.html.slime @@ -1,4 +1,4 @@ -= form_for @changeset, Routes.forum_topic_post_path(@conn, :create, @forum, @topic), fn f -> += form_for @changeset, ~p"/forums/#{@forum}/topics/#{@topic}/posts", fn f -> = if @changeset.action do .alert.alert-danger p Oops, something went wrong! Please check the errors below. diff --git a/lib/philomena_web/templates/topic/post/edit.html.slime b/lib/philomena_web/templates/topic/post/edit.html.slime index 5f815ff2..b7544121 100644 --- a/lib/philomena_web/templates/topic/post/edit.html.slime +++ b/lib/philomena_web/templates/topic/post/edit.html.slime @@ -1,4 +1,4 @@ -= form_for @changeset, Routes.forum_topic_post_path(@conn, :update, @post.topic.forum, @post.topic, @post), fn f -> += form_for @changeset, ~p"/forums/#{@post.topic.forum}/topics/#{@post.topic}/posts/#{@post}", fn f -> = if @changeset.action do .alert.alert-danger p Oops, something went wrong! Please check the errors below. diff --git a/lib/philomena_web/templates/topic/post/history/index.html.slime b/lib/philomena_web/templates/topic/post/history/index.html.slime index c2423ed6..e455ff57 100644 --- a/lib/philomena_web/templates/topic/post/history/index.html.slime +++ b/lib/philomena_web/templates/topic/post/history/index.html.slime @@ -2,7 +2,7 @@ h1 ' Viewing last 25 versions of post by = render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: @post, conn: @conn ' in topic - a href=(Routes.forum_topic_path(@conn, :show, @post.topic.forum, @post.topic, post_id: @post.id) <> "#post_#{@post.id}") + a href=(~p"/forums/#{@post.topic.forum}/topics/#{@post.topic}?#{[post_id: @post.id]}" <> "#post_#{@post.id}") = @post.topic.title = for version <- @versions do diff --git a/lib/philomena_web/templates/topic/show.html.slime b/lib/philomena_web/templates/topic/show.html.slime index ff54dffd..613db6d7 100644 --- a/lib/philomena_web/templates/topic/show.html.slime +++ b/lib/philomena_web/templates/topic/show.html.slime @@ -1,4 +1,4 @@ -- route = fn p -> Routes.forum_topic_path(@conn, :show, @forum, @topic, p) end +- route = fn p -> ~p"/forums/#{@forum}/topics/#{@topic}?#{p}" end - pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @posts, route: route, last: true h1 = @topic.title @@ -16,22 +16,22 @@ h1 = @topic.title strong> Deleted by: em strong - = link(@topic.deleted_by.name, to: Routes.profile_path(@conn, :show, @topic.deleted_by)) + = link(@topic.deleted_by.name, to: ~p"/profiles/#{@topic.deleted_by}") p - = link(to: Routes.forum_topic_hide_path(@conn, :delete, @forum, @topic), method: :delete, class: "button") do + = link(to: ~p"/forums/#{@forum}/topics/#{@topic}/hide", method: :delete, class: "button") do i.fas.fa-check> ' Restore / Header section .block .block__header - => link(@forum.name, to: Routes.forum_path(@conn, :show, @forum)) + => link(@forum.name, to: ~p"/forums/#{@forum}") ' » - => link(@topic.title, to: Routes.forum_topic_path(@conn, :show, @forum, @topic)) + => link(@topic.title, to: ~p"/forums/#{@forum}/topics/#{@topic}") = if not @topic.hidden_from_users or can?(@conn, :hide, @topic) do - a href=Routes.post_path(@conn, :index, pq: "topic_id:#{@topic.id}") + a href=~p"/posts?#{[pq: "topic_id:#{@topic.id}"]}" i.fa.fa-fw.fa-search> ' Search Posts .flex.flex--wrap.block__header.block__header--light.page__header @@ -86,7 +86,7 @@ h1 = @topic.title ' Locked by: em strong - = link(@topic.locked_by.name, to: Routes.profile_path(@conn, :show, @topic.locked_by)) + = link(@topic.locked_by.name, to: ~p"/profiles/#{@topic.locked_by}") / Post form = cond do @@ -116,43 +116,43 @@ h1 = @topic.title p = if not @topic.hidden_from_users do = if @topic.sticky do - = link(to: Routes.forum_topic_stick_path(@conn, :delete, @forum, @topic), method: :delete, class: "button") do + = link(to: ~p"/forums/#{@forum}/topics/#{@topic}/stick", method: :delete, class: "button") do i.fas.fa-thumbtack> ' Unstick - else - = link(to: Routes.forum_topic_stick_path(@conn, :create, @forum, @topic), method: :post, class: "button") do + = link(to: ~p"/forums/#{@forum}/topics/#{@topic}/stick", method: :post, class: "button") do i.fas.fa-thumbtack> ' Stick = if @topic.locked_at do - = link(to: Routes.forum_topic_lock_path(@conn, :delete, @forum, @topic), method: :delete, class: "button") do + = link(to: ~p"/forums/#{@forum}/topics/#{@topic}/lock", method: :delete, class: "button") do i.fas.fa-unlock> ' Unlock - else - = form_for :topic, Routes.forum_topic_lock_path(@conn, :create, @forum, @topic), [method: :post, class: "hform"], fn f -> + = form_for :topic, ~p"/forums/#{@forum}/topics/#{@topic}/lock", [method: :post, class: "hform"], fn f -> .field = text_input f, :lock_reason, class: "input hform__text", placeholder: "Lock reason", required: true = submit class: "hform__button button" do i.fas.fa-lock> ' Lock - = form_for @topic_changeset, Routes.forum_topic_path(@conn, :update, @forum, @topic), [method: :put, class: "hform"], fn f -> + = form_for @topic_changeset, ~p"/forums/#{@forum}/topics/#{@topic}", [method: :put, class: "hform"], fn f -> .field = text_input f, :title, class: "input hform__text", placeholder: "New Title" = submit class: "hform__button button" do i.fas.fa-pen> ' Set Title - = form_for :topic, Routes.forum_topic_move_path(@conn, :create, @forum, @topic), [method: :post, class: "hform"], fn f -> + = form_for :topic, ~p"/forums/#{@forum}/topics/#{@topic}/move", [method: :post, class: "hform"], fn f -> .field = select f, :target_forum_id, Enum.map(@conn.assigns.forums, &{&1.name, &1.id}), class: "input hform__text" = submit class: "hform__button button" do i.fas.fa-truck> ' Move - = form_for :topic, Routes.forum_topic_hide_path(@conn, :create, @forum, @topic), [method: :post, class: "hform"], fn f -> + = form_for :topic, ~p"/forums/#{@forum}/topics/#{@topic}/hide", [method: :post, class: "hform"], fn f -> .field = text_input f, :deletion_reason, class: "input hform__text", placeholder: "Deletion reason", required: true = submit class: "hform__button button" do diff --git a/lib/philomena_web/templates/topic/subscription/_subscription.html.slime b/lib/philomena_web/templates/topic/subscription/_subscription.html.slime index 3a2aa6ca..0772283e 100644 --- a/lib/philomena_web/templates/topic/subscription/_subscription.html.slime +++ b/lib/philomena_web/templates/topic/subscription/_subscription.html.slime @@ -1,8 +1,8 @@ elixir: - watch_path = Routes.forum_topic_subscription_path(@conn, :create, @forum, @topic) + watch_path = ~p"/forums/#{@forum}/topics/#{@topic}/subscription" watch_class = if @watching, do: "hidden", else: "" - unwatch_path = Routes.forum_topic_subscription_path(@conn, :delete, @forum, @topic) + unwatch_path = ~p"/forums/#{@forum}/topics/#{@topic}/subscription" unwatch_class = if @watching, do: "", else: "hidden" = if @conn.assigns.current_user do @@ -17,7 +17,7 @@ elixir: span.hide-mobile ' Unsubscribe - else - a href=Routes.session_path(@conn, :new) + a href=~p"/sessions/new" i.fa.fa-bell> span.hide-mobile ' Subscribe diff --git a/lib/philomena_web/templates/unlock/new.html.slime b/lib/philomena_web/templates/unlock/new.html.slime index 5d64af56..9c8e05cc 100644 --- a/lib/philomena_web/templates/unlock/new.html.slime +++ b/lib/philomena_web/templates/unlock/new.html.slime @@ -1,6 +1,6 @@ h1 Resend unlock instructions -= form_for :user, Routes.unlock_path(@conn, :create), fn f -> += form_for :user, ~p"/unlocks", fn f -> .field = email_input f, :email, placeholder: "Email", class: "input", required: true diff --git a/lib/philomena_web/templates/user_attribution/_anon_user.html.slime b/lib/philomena_web/templates/user_attribution/_anon_user.html.slime index b27abcb2..f5914b85 100644 --- a/lib/philomena_web/templates/user_attribution/_anon_user.html.slime +++ b/lib/philomena_web/templates/user_attribution/_anon_user.html.slime @@ -1,13 +1,13 @@ = cond do - not is_nil(@object.user) and not anonymous?(@object) -> strong<> - = link(@object.user.name, to: Routes.profile_path(@conn, :show, @object.user)) + = link(@object.user.name, to: ~p"/profiles/#{@object.user}") = if assigns[:awards] do = render PhilomenaWeb.ProfileView, "_awards.html", awards: @object.user.awards - not is_nil(@object.user) and (can?(@conn, :reveal_anon, @object) and not hide_staff_tools?(@conn)) -> strong<> - = link(anonymous_name(@object, true), to: Routes.profile_path(@conn, :show, @object.user)) + = link(anonymous_name(@object, true), to: ~p"/profiles/#{@object.user}") - true -> strong<> diff --git a/lib/philomena_web/templates/user_attribution/_user.html.slime b/lib/philomena_web/templates/user_attribution/_user.html.slime index e58b85a4..efd160bb 100644 --- a/lib/philomena_web/templates/user_attribution/_user.html.slime +++ b/lib/philomena_web/templates/user_attribution/_user.html.slime @@ -1,5 +1,5 @@ = if !!@object.user do strong<> - = link(@object.user.name, to: Routes.profile_path(@conn, :show, @object.user)) + = link(@object.user.name, to: ~p"/profiles/#{@object.user}") = if assigns[:awards] do = render PhilomenaWeb.ProfileView, "_awards.html", awards: @object.user.awards \ No newline at end of file diff --git a/lib/philomena_web/user_auth.ex b/lib/philomena_web/user_auth.ex index af7166cf..bf45d8b6 100644 --- a/lib/philomena_web/user_auth.ex +++ b/lib/philomena_web/user_auth.ex @@ -196,7 +196,7 @@ defmodule PhilomenaWeb.UserAuth do conn |> put_flash(:error, "You must log in to access this page.") |> maybe_store_return_to() - |> redirect(to: Routes.session_path(conn, :new)) + |> redirect(to: ~p"/sessions/new") |> halt() end end diff --git a/lib/philomena_web/views/admin/mod_note_view.ex b/lib/philomena_web/views/admin/mod_note_view.ex index a873208a..463de66b 100644 --- a/lib/philomena_web/views/admin/mod_note_view.ex +++ b/lib/philomena_web/views/admin/mod_note_view.ex @@ -6,19 +6,19 @@ defmodule PhilomenaWeb.Admin.ModNoteView do alias Philomena.DnpEntries.DnpEntry def link_to_noted_thing(conn, %DnpEntry{tag: tag} = dnp_entry), - do: link("DNP entry for #{tag.name}", to: Routes.dnp_entry_path(conn, :show, dnp_entry)) + do: link("DNP entry for #{tag.name}", to: ~p"/dnp/#{dnp_entry}") def link_to_noted_thing(conn, %Report{user: nil} = report), - do: link("Report #{report.id}", to: Routes.admin_report_path(conn, :show, report)) + do: link("Report #{report.id}", to: ~p"/admin/reports/#{report}") def link_to_noted_thing(conn, %Report{user: user} = report), do: link("Report #{report.id} by #{user.name}", - to: Routes.admin_report_path(conn, :show, report) + to: ~p"/admin/reports/#{report}" ) def link_to_noted_thing(conn, %User{} = user), - do: link("User #{user.name}", to: Routes.profile_path(conn, :show, user)) + do: link("User #{user.name}", to: ~p"/profiles/#{user}") def link_to_noted_thing(_conn, _notable), do: "Item permanently deleted" end diff --git a/lib/philomena_web/views/admin/report_view.ex b/lib/philomena_web/views/admin/report_view.ex index a9cd5bcc..a192c4fd 100644 --- a/lib/philomena_web/views/admin/report_view.ex +++ b/lib/philomena_web/views/admin/report_view.ex @@ -28,10 +28,10 @@ defmodule PhilomenaWeb.Admin.ReportView do def truncated_ip_link(conn, ip) do case to_string(ip) do <> = ip -> - link(string <> "...", to: Routes.ip_profile_path(conn, :show, ip)) + link(string <> "...", to: ~p"/ip_profiles/#{ip}") ip -> - link(ip, to: Routes.ip_profile_path(conn, :show, ip)) + link(ip, to: ~p"/ip_profiles/#{ip}") end end diff --git a/lib/philomena_web/views/conversation_view.ex b/lib/philomena_web/views/conversation_view.ex index 4ce91283..c85902ab 100644 --- a/lib/philomena_web/views/conversation_view.ex +++ b/lib/philomena_web/views/conversation_view.ex @@ -35,6 +35,6 @@ defmodule PhilomenaWeb.ConversationView do def last_message_path(conn, conversation, count) do page = trunc(Float.ceil(count / 25)) - Routes.conversation_path(conn, :show, conversation, page: page) + ~p"/conversations/#{conversation}?#{[page: page]}" end end diff --git a/lib/philomena_web/views/profile_view.ex b/lib/philomena_web/views/profile_view.ex index 2a9fe461..2470d5cf 100644 --- a/lib/philomena_web/views/profile_view.ex +++ b/lib/philomena_web/views/profile_view.ex @@ -83,7 +83,7 @@ defmodule PhilomenaWeb.ProfileView do abbrv = "(" <> abbrv <> ")" - link(abbrv, to: Routes.profile_path(conn, :show, user)) + link(abbrv, to: ~p"/profiles/#{user}") end def user_abbrv(_conn, _user), do: content_tag(:span, "(n/a)") diff --git a/lib/philomena_web/views/report_view.ex b/lib/philomena_web/views/report_view.ex index 27f6f5a2..e33493be 100644 --- a/lib/philomena_web/views/report_view.ex +++ b/lib/philomena_web/views/report_view.ex @@ -42,39 +42,39 @@ defmodule PhilomenaWeb.ReportView do def pretty_state(_report), do: "Open" def link_to_reported_thing(conn, %Image{} = r), - do: link("Image >>#{r.id}", to: Routes.image_path(conn, :show, r)) + do: link("Image >>#{r.id}", to: ~p"/images/#{r}") def link_to_reported_thing(conn, %Comment{} = r), do: link("Comment on image >>#{r.image.id}", - to: Routes.image_path(conn, :show, r.image) <> "#comment_#{r.id}" + to: ~p"/images/#{r.image}" <> "#comment_#{r.id}" ) def link_to_reported_thing(conn, %Conversation{} = r), do: link("Conversation between #{r.from.name} and #{r.to.name}", - to: Routes.conversation_path(conn, :show, r) + to: ~p"/conversations/#{r}" ) def link_to_reported_thing(conn, %Commission{} = r), do: link("#{r.user.name}'s commission page", - to: Routes.profile_commission_path(conn, :show, r.user) + to: ~p"/profiles/#{r.user}/commission" ) def link_to_reported_thing(conn, %Gallery{} = r), - do: link("Gallery '#{r.title}' by #{r.creator.name}", to: Routes.gallery_path(conn, :show, r)) + do: link("Gallery '#{r.title}' by #{r.creator.name}", to: ~p"/galleries/#{r}") def link_to_reported_thing(conn, %Post{} = r), do: link("Post in #{r.topic.title}", to: - Routes.forum_topic_path(conn, :show, r.topic.forum, r.topic, post_id: r.id) <> + ~p"/forums/#{r.topic.forum}/topics/#{r.topic}?#{[post_id: r.id]}" <> "#post_#{r.id}" ) def link_to_reported_thing(conn, %User{} = r), - do: link("User '#{r.name}'", to: Routes.profile_path(conn, :show, r)) + do: link("User '#{r.name}'", to: ~p"/profiles/#{r}") def link_to_reported_thing(_conn, _reportable) do "Reported item permanently destroyed." diff --git a/test/philomena_web/controllers/confirmation_controller_test.exs b/test/philomena_web/controllers/confirmation_controller_test.exs index 55cbb172..049fd6d1 100644 --- a/test/philomena_web/controllers/confirmation_controller_test.exs +++ b/test/philomena_web/controllers/confirmation_controller_test.exs @@ -12,7 +12,7 @@ defmodule PhilomenaWeb.ConfirmationControllerTest do describe "GET /confirmations/new" do test "renders the confirmation page", %{conn: conn} do - conn = get(conn, Routes.confirmation_path(conn, :new)) + conn = get(conn, ~p"/confirmations/new") response = html_response(conn, 200) assert response =~ "

Resend confirmation instructions

" end @@ -22,7 +22,7 @@ defmodule PhilomenaWeb.ConfirmationControllerTest do @tag :capture_log test "sends a new confirmation token", %{conn: conn, user: user} do conn = - post(conn, Routes.confirmation_path(conn, :create), %{ + post(conn, ~p"/confirmations", %{ "user" => %{"email" => user.email} }) @@ -35,7 +35,7 @@ defmodule PhilomenaWeb.ConfirmationControllerTest do Repo.update!(Users.User.confirm_changeset(user)) conn = - post(conn, Routes.confirmation_path(conn, :create), %{ + post(conn, ~p"/confirmations", %{ "user" => %{"email" => user.email} }) @@ -46,7 +46,7 @@ defmodule PhilomenaWeb.ConfirmationControllerTest do test "does not send confirmation token if email is invalid", %{conn: conn} do conn = - post(conn, Routes.confirmation_path(conn, :create), %{ + post(conn, ~p"/confirmations", %{ "user" => %{"email" => "unknown@example.com"} }) @@ -63,14 +63,14 @@ defmodule PhilomenaWeb.ConfirmationControllerTest do Users.deliver_user_confirmation_instructions(user, url) end) - conn = get(conn, Routes.confirmation_path(conn, :show, token)) + conn = get(conn, ~p"/confirmations/#{token}") assert redirected_to(conn) == "/" assert Flash.get(conn.assigns.flash, :info) =~ "Account confirmed successfully" assert Users.get_user!(user.id).confirmed_at refute get_session(conn, :user_token) assert Repo.all(Users.UserToken) == [] - conn = get(conn, Routes.confirmation_path(conn, :show, token)) + conn = get(conn, ~p"/confirmations/#{token}") assert redirected_to(conn) == "/" assert Flash.get(conn.assigns.flash, :error) =~ @@ -78,7 +78,7 @@ defmodule PhilomenaWeb.ConfirmationControllerTest do end test "does not confirm email with invalid token", %{conn: conn, user: user} do - conn = get(conn, Routes.confirmation_path(conn, :show, "oops")) + conn = get(conn, ~p"/confirmations/oops") assert redirected_to(conn) == "/" assert Flash.get(conn.assigns.flash, :error) =~ diff --git a/test/philomena_web/controllers/password_controller_test.exs b/test/philomena_web/controllers/password_controller_test.exs index 4d421f72..b74cf046 100644 --- a/test/philomena_web/controllers/password_controller_test.exs +++ b/test/philomena_web/controllers/password_controller_test.exs @@ -12,7 +12,7 @@ defmodule PhilomenaWeb.PasswordControllerTest do describe "GET /passwords/new" do test "renders the reset password page", %{conn: conn} do - conn = get(conn, Routes.password_path(conn, :new)) + conn = get(conn, ~p"/passwords/new") html_response(conn, 200) end end @@ -21,7 +21,7 @@ defmodule PhilomenaWeb.PasswordControllerTest do @tag :capture_log test "sends a new reset password token", %{conn: conn, user: user} do conn = - post(conn, Routes.password_path(conn, :create), %{ + post(conn, ~p"/passwords", %{ "user" => %{"email" => user.email} }) @@ -32,7 +32,7 @@ defmodule PhilomenaWeb.PasswordControllerTest do test "does not send reset password token if email is invalid", %{conn: conn} do conn = - post(conn, Routes.password_path(conn, :create), %{ + post(conn, ~p"/passwords", %{ "user" => %{"email" => "unknown@example.com"} }) @@ -53,12 +53,12 @@ defmodule PhilomenaWeb.PasswordControllerTest do end test "renders reset password", %{conn: conn, token: token} do - conn = get(conn, Routes.password_path(conn, :edit, token)) + conn = get(conn, ~p"/passwords/#{token}/edit") html_response(conn, 200) end test "does not render reset password with invalid token", %{conn: conn} do - conn = get(conn, Routes.password_path(conn, :edit, "oops")) + conn = get(conn, ~p"/passwords/oops/edit") assert redirected_to(conn) == "/" assert Flash.get(conn.assigns.flash, :error) =~ @@ -78,14 +78,14 @@ defmodule PhilomenaWeb.PasswordControllerTest do test "resets password once", %{conn: conn, user: user, token: token} do conn = - put(conn, Routes.password_path(conn, :update, token), %{ + put(conn, ~p"/passwords/#{token}", %{ "user" => %{ "password" => "new valid password", "password_confirmation" => "new valid password" } }) - assert redirected_to(conn) == Routes.session_path(conn, :new) + assert redirected_to(conn) == ~p"/sessions/new" refute get_session(conn, :user_token) assert Flash.get(conn.assigns.flash, :info) =~ "Password reset successfully" assert Users.get_user_by_email_and_password(user.email, "new valid password", & &1) @@ -93,7 +93,7 @@ defmodule PhilomenaWeb.PasswordControllerTest do test "does not reset password on invalid data", %{conn: conn, token: token} do conn = - put(conn, Routes.password_path(conn, :update, token), %{ + put(conn, ~p"/passwords/#{token}", %{ "user" => %{ "password" => "too short", "password_confirmation" => "does not match" @@ -106,7 +106,7 @@ defmodule PhilomenaWeb.PasswordControllerTest do end test "does not reset password with invalid token", %{conn: conn} do - conn = put(conn, Routes.password_path(conn, :update, "oops")) + conn = put(conn, ~p"/passwords/oops") assert redirected_to(conn) == "/" assert Flash.get(conn.assigns.flash, :error) =~ diff --git a/test/philomena_web/controllers/registration/email_controller_test.exs b/test/philomena_web/controllers/registration/email_controller_test.exs index 2107a80f..756fea2e 100644 --- a/test/philomena_web/controllers/registration/email_controller_test.exs +++ b/test/philomena_web/controllers/registration/email_controller_test.exs @@ -11,19 +11,19 @@ defmodule PhilomenaWeb.Registration.EmailControllerTest do @tag :capture_log test "updates the user email", %{conn: conn, user: user} do conn = - post(conn, Routes.registration_email_path(conn, :create), %{ + post(conn, ~p"/registrations/email", %{ "current_password" => valid_user_password(), "user" => %{"email" => unique_user_email()} }) - assert redirected_to(conn) == Routes.registration_path(conn, :edit) + assert redirected_to(conn) == ~p"/registrations/edit" assert Flash.get(conn.assigns.flash, :info) =~ "A link to confirm your email" assert Users.get_user_by_email(user.email) end test "does not update email on invalid data", %{conn: conn} do conn = - post(conn, Routes.registration_email_path(conn, :create), %{ + post(conn, ~p"/registrations/email", %{ "current_password" => "invalid", "user" => %{"email" => "with spaces"} }) @@ -45,22 +45,22 @@ defmodule PhilomenaWeb.Registration.EmailControllerTest do end test "updates the user email once", %{conn: conn, user: user, token: token, email: email} do - conn = get(conn, Routes.registration_email_path(conn, :show, token)) - assert redirected_to(conn) == Routes.registration_path(conn, :edit) + conn = get(conn, ~p"/registrations/email/#{token}") + assert redirected_to(conn) == ~p"/registrations/edit" assert Flash.get(conn.assigns.flash, :info) =~ "Email changed successfully" refute Users.get_user_by_email(user.email) assert Users.get_user_by_email(email) - conn = get(conn, Routes.registration_email_path(conn, :show, token)) - assert redirected_to(conn) == Routes.registration_path(conn, :edit) + conn = get(conn, ~p"/registrations/email/#{token}") + assert redirected_to(conn) == ~p"/registrations/edit" assert Flash.get(conn.assigns.flash, :error) =~ "Email change link is invalid or it has expired" end test "does not update email with invalid token", %{conn: conn, user: user} do - conn = get(conn, Routes.registration_email_path(conn, :show, "oops")) - assert redirected_to(conn) == Routes.registration_path(conn, :edit) + conn = get(conn, ~p"/registrations/email/oops") + assert redirected_to(conn) == ~p"/registrations/edit" assert Flash.get(conn.assigns.flash, :error) =~ "Email change link is invalid or it has expired" @@ -70,8 +70,8 @@ defmodule PhilomenaWeb.Registration.EmailControllerTest do test "redirects if user is not logged in", %{token: token} do conn = build_conn() - conn = get(conn, Routes.registration_email_path(conn, :show, token)) - assert redirected_to(conn) == Routes.session_path(conn, :new) + conn = get(conn, ~p"/registrations/email/#{token}") + assert redirected_to(conn) == ~p"/sessions/new" end end end diff --git a/test/philomena_web/controllers/registration/password_controller_test.exs b/test/philomena_web/controllers/registration/password_controller_test.exs index 3e216805..b850e7af 100644 --- a/test/philomena_web/controllers/registration/password_controller_test.exs +++ b/test/philomena_web/controllers/registration/password_controller_test.exs @@ -10,7 +10,7 @@ defmodule PhilomenaWeb.Registration.PasswordControllerTest do describe "PUT /registrations/password" do test "updates the user password and resets tokens", %{conn: conn, user: user} do new_password_conn = - put(conn, Routes.registration_password_path(conn, :update), %{ + put(conn, ~p"/registrations/password", %{ "current_password" => valid_user_password(), "user" => %{ "password" => "new valid password", @@ -18,7 +18,7 @@ defmodule PhilomenaWeb.Registration.PasswordControllerTest do } }) - assert redirected_to(new_password_conn) == Routes.registration_path(conn, :edit) + assert redirected_to(new_password_conn) == ~p"/registrations/edit" assert get_session(new_password_conn, :user_token) != get_session(conn, :user_token) assert Flash.get(new_password_conn.assigns.flash, :info) =~ "Password updated successfully" assert Users.get_user_by_email_and_password(user.email, "new valid password", & &1) @@ -26,7 +26,7 @@ defmodule PhilomenaWeb.Registration.PasswordControllerTest do test "does not update password on invalid data", %{conn: conn} do old_password_conn = - put(conn, Routes.registration_password_path(conn, :update), %{ + put(conn, ~p"/registrations/password", %{ "current_password" => "invalid", "user" => %{ "password" => "too short", @@ -34,7 +34,7 @@ defmodule PhilomenaWeb.Registration.PasswordControllerTest do } }) - assert redirected_to(old_password_conn) == Routes.registration_path(conn, :edit) + assert redirected_to(old_password_conn) == ~p"/registrations/edit" assert Flash.get(old_password_conn.assigns.flash, :error) =~ "Failed to update password" assert get_session(old_password_conn, :user_token) == get_session(conn, :user_token) end diff --git a/test/philomena_web/controllers/registration_controller_test.exs b/test/philomena_web/controllers/registration_controller_test.exs index 0ee59d90..dc557666 100644 --- a/test/philomena_web/controllers/registration_controller_test.exs +++ b/test/philomena_web/controllers/registration_controller_test.exs @@ -5,13 +5,13 @@ defmodule PhilomenaWeb.RegistrationControllerTest do describe "GET /registrations/new" do test "renders registration page", %{conn: conn} do - conn = get(conn, Routes.registration_path(conn, :new)) + conn = get(conn, ~p"/registrations/new") html_response(conn, 200) end test "redirects if already logged in", %{conn: conn} do conn = - conn |> log_in_user(confirmed_user_fixture()) |> get(Routes.registration_path(conn, :new)) + conn |> log_in_user(confirmed_user_fixture()) |> get(~p"/registrations/new") assert redirected_to(conn) == "/" end @@ -23,7 +23,7 @@ defmodule PhilomenaWeb.RegistrationControllerTest do email = unique_user_email() conn = - post(conn, Routes.registration_path(conn, :create), %{ + post(conn, ~p"/registrations", %{ "user" => %{"name" => email, "email" => email, "password" => valid_user_password()} }) @@ -36,7 +36,7 @@ defmodule PhilomenaWeb.RegistrationControllerTest do test "render errors for invalid data", %{conn: conn} do conn = - post(conn, Routes.registration_path(conn, :create), %{ + post(conn, ~p"/registrations", %{ "user" => %{"email" => "with spaces", "password" => "too short"} }) @@ -50,15 +50,15 @@ defmodule PhilomenaWeb.RegistrationControllerTest do setup :register_and_log_in_user test "renders settings page", %{conn: conn} do - conn = get(conn, Routes.registration_path(conn, :edit)) + conn = get(conn, ~p"/registrations/edit") response = html_response(conn, 200) assert response =~ "Settings" end test "redirects if user is not logged in" do conn = build_conn() - conn = get(conn, Routes.registration_path(conn, :edit)) - assert redirected_to(conn) == Routes.session_path(conn, :new) + conn = get(conn, ~p"/registrations/edit") + assert redirected_to(conn) == ~p"/sessions/new" end end end diff --git a/test/philomena_web/controllers/session_controller_test.exs b/test/philomena_web/controllers/session_controller_test.exs index 78e14834..29d8d7f2 100644 --- a/test/philomena_web/controllers/session_controller_test.exs +++ b/test/philomena_web/controllers/session_controller_test.exs @@ -9,12 +9,12 @@ defmodule PhilomenaWeb.SessionControllerTest do describe "GET /sessions/new" do test "renders log in page", %{conn: conn} do - conn = get(conn, Routes.session_path(conn, :new)) + conn = get(conn, ~p"/sessions/new") html_response(conn, 200) end test "redirects if already logged in", %{conn: conn, user: user} do - conn = conn |> log_in_user(user) |> get(Routes.session_path(conn, :new)) + conn = conn |> log_in_user(user) |> get(~p"/sessions/new") assert redirected_to(conn) == "/" end end @@ -22,7 +22,7 @@ defmodule PhilomenaWeb.SessionControllerTest do describe "POST /sessions" do test "logs the user in", %{conn: conn, user: user} do conn = - post(conn, Routes.session_path(conn, :create), %{ + post(conn, ~p"/sessions", %{ "user" => %{"email" => user.email, "password" => valid_user_password()} }) @@ -39,7 +39,7 @@ defmodule PhilomenaWeb.SessionControllerTest do test "logs the user in with remember me", %{conn: conn, user: user} do conn = - post(conn, Routes.session_path(conn, :create), %{ + post(conn, ~p"/sessions", %{ "user" => %{ "email" => user.email, "password" => valid_user_password(), @@ -53,7 +53,7 @@ defmodule PhilomenaWeb.SessionControllerTest do test "emits error message with invalid credentials", %{conn: conn, user: user} do conn = - post(conn, Routes.session_path(conn, :create), %{ + post(conn, ~p"/sessions", %{ "user" => %{"email" => user.email, "password" => "invalid_password"} }) @@ -64,7 +64,7 @@ defmodule PhilomenaWeb.SessionControllerTest do describe "DELETE /sessions" do test "logs the user out", %{conn: conn, user: user} do - conn = conn |> log_in_user(user) |> delete(Routes.session_path(conn, :delete)) + conn = conn |> log_in_user(user) |> delete(~p"/sessions") assert redirected_to(conn) == "/" refute get_session(conn, :user_token) assert Phoenix.Flash.get(conn.assigns.flash, :info) =~ "Logged out successfully" diff --git a/test/philomena_web/controllers/unlock_controller_test.exs b/test/philomena_web/controllers/unlock_controller_test.exs index d506e90a..bc8df85e 100644 --- a/test/philomena_web/controllers/unlock_controller_test.exs +++ b/test/philomena_web/controllers/unlock_controller_test.exs @@ -12,7 +12,7 @@ defmodule PhilomenaWeb.UnlockControllerTest do describe "GET /unlocks/new" do test "renders the unlock page", %{conn: conn} do - conn = get(conn, Routes.unlock_path(conn, :new)) + conn = get(conn, ~p"/unlocks/new") response = html_response(conn, 200) assert response =~ "

Resend unlock instructions

" end @@ -22,7 +22,7 @@ defmodule PhilomenaWeb.UnlockControllerTest do @tag :capture_log test "sends a new unlock token", %{conn: conn, user: user} do conn = - post(conn, Routes.unlock_path(conn, :create), %{ + post(conn, ~p"/unlocks", %{ "user" => %{"email" => user.email} }) @@ -35,7 +35,7 @@ defmodule PhilomenaWeb.UnlockControllerTest do Repo.update!(Users.User.unlock_changeset(user)) conn = - post(conn, Routes.unlock_path(conn, :create), %{ + post(conn, ~p"/unlocks", %{ "user" => %{"email" => user.email} }) @@ -46,7 +46,7 @@ defmodule PhilomenaWeb.UnlockControllerTest do test "does not send unlock token if email is invalid", %{conn: conn} do conn = - post(conn, Routes.unlock_path(conn, :create), %{ + post(conn, ~p"/unlocks", %{ "user" => %{"email" => "unknown@example.com"} }) @@ -63,20 +63,20 @@ defmodule PhilomenaWeb.UnlockControllerTest do Users.deliver_user_unlock_instructions(user, url) end) - conn = get(conn, Routes.unlock_path(conn, :show, token)) + conn = get(conn, ~p"/unlocks/#{token}") assert redirected_to(conn) == "/" assert Flash.get(conn.assigns.flash, :info) =~ "Account unlocked successfully" refute Users.get_user!(user.id).locked_at refute get_session(conn, :user_token) assert Repo.all(Users.UserToken) == [] - conn = get(conn, Routes.unlock_path(conn, :show, token)) + conn = get(conn, ~p"/unlocks/#{token}") assert redirected_to(conn) == "/" assert Flash.get(conn.assigns.flash, :error) =~ "Unlock link is invalid or it has expired" end test "does not unlock with invalid token", %{conn: conn, user: user} do - conn = get(conn, Routes.unlock_path(conn, :show, "oops")) + conn = get(conn, ~p"/unlocks/oops") assert redirected_to(conn) == "/" assert Flash.get(conn.assigns.flash, :error) =~ "Unlock link is invalid or it has expired" assert Users.get_user!(user.id).locked_at diff --git a/test/philomena_web/user_auth_test.exs b/test/philomena_web/user_auth_test.exs index e03912fe..deeaeca7 100644 --- a/test/philomena_web/user_auth_test.exs +++ b/test/philomena_web/user_auth_test.exs @@ -162,7 +162,7 @@ defmodule PhilomenaWeb.UserAuthTest do test "redirects if user is not authenticated", %{conn: conn} do conn = conn |> fetch_flash() |> UserAuth.require_authenticated_user([]) assert conn.halted - assert redirected_to(conn) == Routes.session_path(conn, :new) + assert redirected_to(conn) == ~p"/sessions/new" assert Phoenix.Flash.get(conn.assigns.flash, :error) == "You must log in to access this page." From c1fcfe1f6c524c72bf9cd0463d0dc90736f83ac8 Mon Sep 17 00:00:00 2001 From: Liam Date: Sun, 28 Apr 2024 21:03:37 -0400 Subject: [PATCH 07/35] find lib/ -name '*.ex' -exec sed -i 's|defp log_details(conn, |defp log_details(_conn, |g' {} \; --- .../controllers/admin/artist_link/contact_controller.ex | 2 +- .../controllers/admin/artist_link/reject_controller.ex | 2 +- .../controllers/admin/artist_link/verification_controller.ex | 2 +- lib/philomena_web/controllers/admin/batch/tag_controller.ex | 2 +- .../controllers/admin/fingerprint_ban_controller.ex | 2 +- lib/philomena_web/controllers/admin/subnet_ban_controller.ex | 2 +- .../controllers/admin/user/verification_controller.ex | 2 +- lib/philomena_web/controllers/admin/user_ban_controller.ex | 2 +- lib/philomena_web/controllers/admin/user_controller.ex | 2 +- .../controllers/duplicate_report/accept_controller.ex | 2 +- .../controllers/duplicate_report/accept_reverse_controller.ex | 2 +- .../controllers/duplicate_report/claim_controller.ex | 2 +- .../controllers/duplicate_report/reject_controller.ex | 2 +- lib/philomena_web/controllers/image/anonymous_controller.ex | 2 +- lib/philomena_web/controllers/image/approve_controller.ex | 2 +- .../controllers/image/comment/approve_controller.ex | 2 +- .../controllers/image/comment/delete_controller.ex | 2 +- lib/philomena_web/controllers/image/comment/hide_controller.ex | 2 +- lib/philomena_web/controllers/image/comment_lock_controller.ex | 2 +- lib/philomena_web/controllers/image/delete_controller.ex | 2 +- .../controllers/image/description_lock_controller.ex | 2 +- lib/philomena_web/controllers/image/destroy_controller.ex | 2 +- lib/philomena_web/controllers/image/feature_controller.ex | 2 +- lib/philomena_web/controllers/image/hash_controller.ex | 2 +- lib/philomena_web/controllers/image/repair_controller.ex | 2 +- lib/philomena_web/controllers/image/scratchpad_controller.ex | 2 +- .../controllers/image/source_history_controller.ex | 2 +- lib/philomena_web/controllers/image/tag_change_controller.ex | 2 +- lib/philomena_web/controllers/image/tag_lock_controller.ex | 2 +- lib/philomena_web/controllers/image/tamper_controller.ex | 2 +- lib/philomena_web/controllers/tag/image_controller.ex | 2 +- lib/philomena_web/controllers/tag_controller.ex | 2 +- lib/philomena_web/controllers/topic/hide_controller.ex | 2 +- lib/philomena_web/controllers/topic/lock_controller.ex | 2 +- lib/philomena_web/controllers/topic/move_controller.ex | 2 +- lib/philomena_web/controllers/topic/post/approve_controller.ex | 2 +- lib/philomena_web/controllers/topic/post/delete_controller.ex | 2 +- lib/philomena_web/controllers/topic/post/hide_controller.ex | 2 +- lib/philomena_web/controllers/topic/stick_controller.ex | 2 +- 39 files changed, 39 insertions(+), 39 deletions(-) diff --git a/lib/philomena_web/controllers/admin/artist_link/contact_controller.ex b/lib/philomena_web/controllers/admin/artist_link/contact_controller.ex index 0e0ffc30..2f270db8 100644 --- a/lib/philomena_web/controllers/admin/artist_link/contact_controller.ex +++ b/lib/philomena_web/controllers/admin/artist_link/contact_controller.ex @@ -22,7 +22,7 @@ defmodule PhilomenaWeb.Admin.ArtistLink.ContactController do |> redirect(to: ~p"/admin/artist_links") end - defp log_details(conn, _action, artist_link) do + defp log_details(_conn, _action, artist_link) do %{ body: "Contacted artist #{artist_link.user.name} at #{artist_link.uri}", subject_path: ~p"/profiles/#{artist_link.user}/artist_links/#{artist_link}" diff --git a/lib/philomena_web/controllers/admin/artist_link/reject_controller.ex b/lib/philomena_web/controllers/admin/artist_link/reject_controller.ex index 168251fd..b238efcf 100644 --- a/lib/philomena_web/controllers/admin/artist_link/reject_controller.ex +++ b/lib/philomena_web/controllers/admin/artist_link/reject_controller.ex @@ -21,7 +21,7 @@ defmodule PhilomenaWeb.Admin.ArtistLink.RejectController do |> redirect(to: ~p"/admin/artist_links") end - defp log_details(conn, _action, artist_link) do + defp log_details(_conn, _action, artist_link) do %{ body: "Rejected artist link #{artist_link.uri} created by #{artist_link.user.name}", subject_path: ~p"/profiles/#{artist_link.user}/artist_links/#{artist_link}" diff --git a/lib/philomena_web/controllers/admin/artist_link/verification_controller.ex b/lib/philomena_web/controllers/admin/artist_link/verification_controller.ex index 02a45ab4..836b59d7 100644 --- a/lib/philomena_web/controllers/admin/artist_link/verification_controller.ex +++ b/lib/philomena_web/controllers/admin/artist_link/verification_controller.ex @@ -22,7 +22,7 @@ defmodule PhilomenaWeb.Admin.ArtistLink.VerificationController do |> redirect(to: ~p"/admin/artist_links") end - defp log_details(conn, _action, artist_link) do + defp log_details(_conn, _action, artist_link) do %{ body: "Verified artist link #{artist_link.uri} created by #{artist_link.user.name}", subject_path: ~p"/profiles/#{artist_link.user}/artist_links/#{artist_link}" diff --git a/lib/philomena_web/controllers/admin/batch/tag_controller.ex b/lib/philomena_web/controllers/admin/batch/tag_controller.ex index 59371b6a..512a0972 100644 --- a/lib/philomena_web/controllers/admin/batch/tag_controller.ex +++ b/lib/philomena_web/controllers/admin/batch/tag_controller.ex @@ -68,7 +68,7 @@ defmodule PhilomenaWeb.Admin.Batch.TagController do end end - defp log_details(conn, _action, data) do + defp log_details(_conn, _action, data) do %{ body: "Batch tagged '#{data.tag_list}' on #{data.image_count} images", subject_path: ~p"/profiles/#{conn.assigns.current_user}" diff --git a/lib/philomena_web/controllers/admin/fingerprint_ban_controller.ex b/lib/philomena_web/controllers/admin/fingerprint_ban_controller.ex index 2e1c20f9..3ae57571 100644 --- a/lib/philomena_web/controllers/admin/fingerprint_ban_controller.ex +++ b/lib/philomena_web/controllers/admin/fingerprint_ban_controller.ex @@ -110,7 +110,7 @@ defmodule PhilomenaWeb.Admin.FingerprintBanController do end end - defp log_details(conn, action, ban) do + defp log_details(_conn, action, ban) do body = case action do :create -> "Created a fingerprint ban #{ban.generated_ban_id}" diff --git a/lib/philomena_web/controllers/admin/subnet_ban_controller.ex b/lib/philomena_web/controllers/admin/subnet_ban_controller.ex index f2d0dbaa..31f83b07 100644 --- a/lib/philomena_web/controllers/admin/subnet_ban_controller.ex +++ b/lib/philomena_web/controllers/admin/subnet_ban_controller.ex @@ -112,7 +112,7 @@ defmodule PhilomenaWeb.Admin.SubnetBanController do end end - defp log_details(conn, action, ban) do + defp log_details(_conn, action, ban) do body = case action do :create -> "Created a subnet ban #{ban.generated_ban_id}" diff --git a/lib/philomena_web/controllers/admin/user/verification_controller.ex b/lib/philomena_web/controllers/admin/user/verification_controller.ex index 9478bc42..5f8864ee 100644 --- a/lib/philomena_web/controllers/admin/user/verification_controller.ex +++ b/lib/philomena_web/controllers/admin/user/verification_controller.ex @@ -32,7 +32,7 @@ defmodule PhilomenaWeb.Admin.User.VerificationController do end end - defp log_details(conn, action, user) do + defp log_details(_conn, action, user) do body = case action do :create -> "Granted verification to #{user.name}" diff --git a/lib/philomena_web/controllers/admin/user_ban_controller.ex b/lib/philomena_web/controllers/admin/user_ban_controller.ex index bbaf6b62..7def2541 100644 --- a/lib/philomena_web/controllers/admin/user_ban_controller.ex +++ b/lib/philomena_web/controllers/admin/user_ban_controller.ex @@ -116,7 +116,7 @@ defmodule PhilomenaWeb.Admin.UserBanController do end end - defp log_details(conn, action, ban) do + defp log_details(_conn, action, ban) do body = case action do :create -> "Created a user ban #{ban.generated_ban_id}" diff --git a/lib/philomena_web/controllers/admin/user_controller.ex b/lib/philomena_web/controllers/admin/user_controller.ex index 672147f8..5f236108 100644 --- a/lib/philomena_web/controllers/admin/user_controller.ex +++ b/lib/philomena_web/controllers/admin/user_controller.ex @@ -81,7 +81,7 @@ defmodule PhilomenaWeb.Admin.UserController do assign(conn, :roles, Repo.all(Role)) end - defp log_details(conn, _action, user) do + defp log_details(_conn, _action, user) do %{ body: "Updated user details for #{user.name}", subject_path: ~p"/profiles/#{user}" diff --git a/lib/philomena_web/controllers/duplicate_report/accept_controller.ex b/lib/philomena_web/controllers/duplicate_report/accept_controller.ex index a67760dc..4462fb38 100644 --- a/lib/philomena_web/controllers/duplicate_report/accept_controller.ex +++ b/lib/philomena_web/controllers/duplicate_report/accept_controller.ex @@ -30,7 +30,7 @@ defmodule PhilomenaWeb.DuplicateReport.AcceptController do end end - defp log_details(conn, _action, report) do + defp log_details(_conn, _action, report) do %{ body: "Accepted duplicate report, merged #{report.image.id} into #{report.duplicate_of_image.id}", diff --git a/lib/philomena_web/controllers/duplicate_report/accept_reverse_controller.ex b/lib/philomena_web/controllers/duplicate_report/accept_reverse_controller.ex index 7c04cc49..873768ff 100644 --- a/lib/philomena_web/controllers/duplicate_report/accept_reverse_controller.ex +++ b/lib/philomena_web/controllers/duplicate_report/accept_reverse_controller.ex @@ -30,7 +30,7 @@ defmodule PhilomenaWeb.DuplicateReport.AcceptReverseController do end end - defp log_details(conn, _action, report) do + defp log_details(_conn, _action, report) do %{ body: "Reverse-accepted duplicate report, merged #{report.image.id} into #{report.duplicate_of_image.id}", diff --git a/lib/philomena_web/controllers/duplicate_report/claim_controller.ex b/lib/philomena_web/controllers/duplicate_report/claim_controller.ex index 966eddae..446fa367 100644 --- a/lib/philomena_web/controllers/duplicate_report/claim_controller.ex +++ b/lib/philomena_web/controllers/duplicate_report/claim_controller.ex @@ -33,7 +33,7 @@ defmodule PhilomenaWeb.DuplicateReport.ClaimController do |> redirect(to: ~p"/duplicate_reports") end - defp log_details(conn, action, _) do + defp log_details(_conn, action, _) do body = case action do :create -> "Claimed a duplicate report" diff --git a/lib/philomena_web/controllers/duplicate_report/reject_controller.ex b/lib/philomena_web/controllers/duplicate_report/reject_controller.ex index 83626c36..7d428e52 100644 --- a/lib/philomena_web/controllers/duplicate_report/reject_controller.ex +++ b/lib/philomena_web/controllers/duplicate_report/reject_controller.ex @@ -25,7 +25,7 @@ defmodule PhilomenaWeb.DuplicateReport.RejectController do |> redirect(to: ~p"/duplicate_reports") end - defp log_details(conn, _action, report) do + defp log_details(_conn, _action, report) do %{ body: "Rejected duplicate report (#{report.image.id} -> #{report.duplicate_of_image.id})", subject_path: ~p"/duplicate_reports" diff --git a/lib/philomena_web/controllers/image/anonymous_controller.ex b/lib/philomena_web/controllers/image/anonymous_controller.ex index 1855efc9..feed3ff1 100644 --- a/lib/philomena_web/controllers/image/anonymous_controller.ex +++ b/lib/philomena_web/controllers/image/anonymous_controller.ex @@ -33,7 +33,7 @@ defmodule PhilomenaWeb.Image.AnonymousController do end end - defp log_details(conn, _action, image) do + defp log_details(_conn, _action, image) do %{ body: "Updated anonymity of image >>#{image.id}", subject_path: ~p"/images/#{image}" diff --git a/lib/philomena_web/controllers/image/approve_controller.ex b/lib/philomena_web/controllers/image/approve_controller.ex index 1a44cb76..b67b9619 100644 --- a/lib/philomena_web/controllers/image/approve_controller.ex +++ b/lib/philomena_web/controllers/image/approve_controller.ex @@ -18,7 +18,7 @@ defmodule PhilomenaWeb.Image.ApproveController do |> redirect(to: ~p"/admin/approvals") end - defp log_details(conn, _action, image) do + defp log_details(_conn, _action, image) do %{body: "Approved image #{image.id}", subject_path: ~p"/images/#{image}"} end end diff --git a/lib/philomena_web/controllers/image/comment/approve_controller.ex b/lib/philomena_web/controllers/image/comment/approve_controller.ex index f6b05ca1..c55e734c 100644 --- a/lib/philomena_web/controllers/image/comment/approve_controller.ex +++ b/lib/philomena_web/controllers/image/comment/approve_controller.ex @@ -26,7 +26,7 @@ defmodule PhilomenaWeb.Image.Comment.ApproveController do |> redirect(to: ~p"/images/#{comment.image_id}" <> "#comment_#{comment.id}") end - defp log_details(conn, _action, comment) do + defp log_details(_conn, _action, comment) do %{ body: "Approved comment on image >>#{comment.image_id}", subject_path: ~p"/images/#{comment.image_id}" <> "#comment_#{comment.id}" diff --git a/lib/philomena_web/controllers/image/comment/delete_controller.ex b/lib/philomena_web/controllers/image/comment/delete_controller.ex index 21fc2c1f..65e80700 100644 --- a/lib/philomena_web/controllers/image/comment/delete_controller.ex +++ b/lib/philomena_web/controllers/image/comment/delete_controller.ex @@ -26,7 +26,7 @@ defmodule PhilomenaWeb.Image.Comment.DeleteController do end end - defp log_details(conn, _action, comment) do + defp log_details(_conn, _action, comment) do %{ body: "Destroyed comment on image >>#{comment.image_id}", subject_path: ~p"/images/#{comment.image_id}" <> "#comment_#{comment.id}" diff --git a/lib/philomena_web/controllers/image/comment/hide_controller.ex b/lib/philomena_web/controllers/image/comment/hide_controller.ex index 94241104..50a10f57 100644 --- a/lib/philomena_web/controllers/image/comment/hide_controller.ex +++ b/lib/philomena_web/controllers/image/comment/hide_controller.ex @@ -42,7 +42,7 @@ defmodule PhilomenaWeb.Image.Comment.HideController do end end - defp log_details(conn, action, comment) do + defp log_details(_conn, action, comment) do body = case action do :create -> "Hidden comment on image >>#{comment.image_id} (#{comment.deletion_reason})" diff --git a/lib/philomena_web/controllers/image/comment_lock_controller.ex b/lib/philomena_web/controllers/image/comment_lock_controller.ex index c6c5b2b9..9256f9b6 100644 --- a/lib/philomena_web/controllers/image/comment_lock_controller.ex +++ b/lib/philomena_web/controllers/image/comment_lock_controller.ex @@ -25,7 +25,7 @@ defmodule PhilomenaWeb.Image.CommentLockController do |> redirect(to: ~p"/images/#{image}") end - defp log_details(conn, action, image) do + defp log_details(_conn, action, image) do body = case action do :create -> "Locked comments on image >>#{image.id}" diff --git a/lib/philomena_web/controllers/image/delete_controller.ex b/lib/philomena_web/controllers/image/delete_controller.ex index 3d86cfa6..a9ccbad8 100644 --- a/lib/philomena_web/controllers/image/delete_controller.ex +++ b/lib/philomena_web/controllers/image/delete_controller.ex @@ -70,7 +70,7 @@ defmodule PhilomenaWeb.Image.DeleteController do |> redirect(to: ~p"/images/#{image}") end - defp log_details(conn, action, image) do + defp log_details(_conn, action, image) do body = case action do :create -> "Hidden image >>#{image.id} (#{image.deletion_reason})" diff --git a/lib/philomena_web/controllers/image/description_lock_controller.ex b/lib/philomena_web/controllers/image/description_lock_controller.ex index bde327ac..e7ddc628 100644 --- a/lib/philomena_web/controllers/image/description_lock_controller.ex +++ b/lib/philomena_web/controllers/image/description_lock_controller.ex @@ -25,7 +25,7 @@ defmodule PhilomenaWeb.Image.DescriptionLockController do |> redirect(to: ~p"/images/#{image}") end - defp log_details(conn, action, image) do + defp log_details(_conn, action, image) do body = case action do :create -> "Locked description editing on image >>#{image.id}" diff --git a/lib/philomena_web/controllers/image/destroy_controller.ex b/lib/philomena_web/controllers/image/destroy_controller.ex index 8f4ed867..986773d0 100644 --- a/lib/philomena_web/controllers/image/destroy_controller.ex +++ b/lib/philomena_web/controllers/image/destroy_controller.ex @@ -38,7 +38,7 @@ defmodule PhilomenaWeb.Image.DestroyController do end end - defp log_details(conn, _action, image) do + defp log_details(_conn, _action, image) do %{ body: "Hard-deleted image >>#{image.id}", subject_path: ~p"/images/#{image}" diff --git a/lib/philomena_web/controllers/image/feature_controller.ex b/lib/philomena_web/controllers/image/feature_controller.ex index 74c19c05..59df5b73 100644 --- a/lib/philomena_web/controllers/image/feature_controller.ex +++ b/lib/philomena_web/controllers/image/feature_controller.ex @@ -33,7 +33,7 @@ defmodule PhilomenaWeb.Image.FeatureController do end end - defp log_details(conn, _action, image) do + defp log_details(_conn, _action, image) do %{ body: "Featured image >>#{image.id}", subject_path: ~p"/images/#{image}" diff --git a/lib/philomena_web/controllers/image/hash_controller.ex b/lib/philomena_web/controllers/image/hash_controller.ex index 233d5202..ffbeb109 100644 --- a/lib/philomena_web/controllers/image/hash_controller.ex +++ b/lib/philomena_web/controllers/image/hash_controller.ex @@ -16,7 +16,7 @@ defmodule PhilomenaWeb.Image.HashController do |> redirect(to: ~p"/images/#{image}") end - defp log_details(conn, _action, image) do + defp log_details(_conn, _action, image) do %{ body: "Cleared hash of image >>#{image.id}", subject_path: ~p"/images/#{image}" diff --git a/lib/philomena_web/controllers/image/repair_controller.ex b/lib/philomena_web/controllers/image/repair_controller.ex index 10d86773..80a050b7 100644 --- a/lib/philomena_web/controllers/image/repair_controller.ex +++ b/lib/philomena_web/controllers/image/repair_controller.ex @@ -17,7 +17,7 @@ defmodule PhilomenaWeb.Image.RepairController do |> redirect(to: ~p"/images/#{conn.assigns.image}") end - defp log_details(conn, _action, image) do + defp log_details(_conn, _action, image) do %{ body: "Repaired image >>#{image.id}", subject_path: ~p"/images/#{image}" diff --git a/lib/philomena_web/controllers/image/scratchpad_controller.ex b/lib/philomena_web/controllers/image/scratchpad_controller.ex index 4fddb135..b3cd8e69 100644 --- a/lib/philomena_web/controllers/image/scratchpad_controller.ex +++ b/lib/philomena_web/controllers/image/scratchpad_controller.ex @@ -21,7 +21,7 @@ defmodule PhilomenaWeb.Image.ScratchpadController do |> redirect(to: ~p"/images/#{image}") end - defp log_details(conn, _action, image) do + defp log_details(_conn, _action, image) do %{ body: "Updated mod notes on image >>#{image.id} (#{image.scratchpad})", subject_path: ~p"/images/#{image}" diff --git a/lib/philomena_web/controllers/image/source_history_controller.ex b/lib/philomena_web/controllers/image/source_history_controller.ex index 85f061db..022a270d 100644 --- a/lib/philomena_web/controllers/image/source_history_controller.ex +++ b/lib/philomena_web/controllers/image/source_history_controller.ex @@ -18,7 +18,7 @@ defmodule PhilomenaWeb.Image.SourceHistoryController do |> redirect(to: ~p"/images/#{image}") end - defp log_details(conn, _action, image) do + defp log_details(_conn, _action, image) do %{ body: "Deleted source history for image >>#{image.id}", subject_path: ~p"/images/#{image}" diff --git a/lib/philomena_web/controllers/image/tag_change_controller.ex b/lib/philomena_web/controllers/image/tag_change_controller.ex index b2716558..b38735ca 100644 --- a/lib/philomena_web/controllers/image/tag_change_controller.ex +++ b/lib/philomena_web/controllers/image/tag_change_controller.ex @@ -58,7 +58,7 @@ defmodule PhilomenaWeb.Image.TagChangeController do defp added_filter(query, _params), do: query - defp log_details(conn, _action, %{image: image, details: details}) do + defp log_details(_conn, _action, %{image: image, details: details}) do %{ body: "Deleted tag change #{details} on >>#{image.id} from history", subject_path: ~p"/images/#{image}" diff --git a/lib/philomena_web/controllers/image/tag_lock_controller.ex b/lib/philomena_web/controllers/image/tag_lock_controller.ex index 4e6a0e70..c80841c7 100644 --- a/lib/philomena_web/controllers/image/tag_lock_controller.ex +++ b/lib/philomena_web/controllers/image/tag_lock_controller.ex @@ -45,7 +45,7 @@ defmodule PhilomenaWeb.Image.TagLockController do |> redirect(to: ~p"/images/#{image}") end - defp log_details(conn, action, image) do + defp log_details(_conn, action, image) do body = case action do :create -> "Locked tags on image >>#{image.id}" diff --git a/lib/philomena_web/controllers/image/tamper_controller.ex b/lib/philomena_web/controllers/image/tamper_controller.ex index 4ce1ac3c..482bb14a 100644 --- a/lib/philomena_web/controllers/image/tamper_controller.ex +++ b/lib/philomena_web/controllers/image/tamper_controller.ex @@ -31,7 +31,7 @@ defmodule PhilomenaWeb.Image.TamperController do |> redirect(to: ~p"/images/#{conn.assigns.image}") end - defp log_details(conn, _action, data) do + defp log_details(_conn, _action, data) do image = data.image vote_type = diff --git a/lib/philomena_web/controllers/tag/image_controller.ex b/lib/philomena_web/controllers/tag/image_controller.ex index 21d06983..96ed3899 100644 --- a/lib/philomena_web/controllers/tag/image_controller.ex +++ b/lib/philomena_web/controllers/tag/image_controller.ex @@ -40,7 +40,7 @@ defmodule PhilomenaWeb.Tag.ImageController do |> redirect(to: ~p"/tags/#{conn.assigns.tag}") end - defp log_details(conn, action, tag) do + defp log_details(_conn, action, tag) do body = case action do :update -> "Updated image on tag '#{tag.name}'" diff --git a/lib/philomena_web/controllers/tag_controller.ex b/lib/philomena_web/controllers/tag_controller.ex index 3fac85cd..2c94d3e5 100644 --- a/lib/philomena_web/controllers/tag_controller.ex +++ b/lib/philomena_web/controllers/tag_controller.ex @@ -172,7 +172,7 @@ defmodule PhilomenaWeb.TagController do end end - defp log_details(conn, action, tag) do + defp log_details(_conn, action, tag) do body = case action do :update -> "Updated details on tag '#{tag.name}'" diff --git a/lib/philomena_web/controllers/topic/hide_controller.ex b/lib/philomena_web/controllers/topic/hide_controller.ex index 247741d5..8eb947cf 100644 --- a/lib/philomena_web/controllers/topic/hide_controller.ex +++ b/lib/philomena_web/controllers/topic/hide_controller.ex @@ -54,7 +54,7 @@ defmodule PhilomenaWeb.Topic.HideController do end end - defp log_details(conn, action, topic) do + defp log_details(_conn, action, topic) do body = case action do :create -> diff --git a/lib/philomena_web/controllers/topic/lock_controller.ex b/lib/philomena_web/controllers/topic/lock_controller.ex index aa4bf13f..9cb95c7f 100644 --- a/lib/philomena_web/controllers/topic/lock_controller.ex +++ b/lib/philomena_web/controllers/topic/lock_controller.ex @@ -53,7 +53,7 @@ defmodule PhilomenaWeb.Topic.LockController do end end - defp log_details(conn, action, topic) do + defp log_details(_conn, action, topic) do body = case action do :create -> "Locked topic '#{topic.title}' (#{topic.lock_reason}) in #{topic.forum.name}" diff --git a/lib/philomena_web/controllers/topic/move_controller.ex b/lib/philomena_web/controllers/topic/move_controller.ex index d8c91c3f..fcd17c21 100644 --- a/lib/philomena_web/controllers/topic/move_controller.ex +++ b/lib/philomena_web/controllers/topic/move_controller.ex @@ -39,7 +39,7 @@ defmodule PhilomenaWeb.Topic.MoveController do end end - defp log_details(conn, _action, topic) do + defp log_details(_conn, _action, topic) do %{ body: "Topic '#{topic.title}' moved to #{topic.forum.name}", subject_path: ~p"/forums/#{topic.forum}/topics/#{topic}" diff --git a/lib/philomena_web/controllers/topic/post/approve_controller.ex b/lib/philomena_web/controllers/topic/post/approve_controller.ex index 01e11daf..1af98931 100644 --- a/lib/philomena_web/controllers/topic/post/approve_controller.ex +++ b/lib/philomena_web/controllers/topic/post/approve_controller.ex @@ -38,7 +38,7 @@ defmodule PhilomenaWeb.Topic.Post.ApproveController do end end - defp log_details(conn, _action, post) do + defp log_details(_conn, _action, post) do %{ body: "Approved forum post ##{post.id} in topic '#{post.topic.title}'", subject_path: diff --git a/lib/philomena_web/controllers/topic/post/delete_controller.ex b/lib/philomena_web/controllers/topic/post/delete_controller.ex index 72e39536..9fa2b490 100644 --- a/lib/philomena_web/controllers/topic/post/delete_controller.ex +++ b/lib/philomena_web/controllers/topic/post/delete_controller.ex @@ -37,7 +37,7 @@ defmodule PhilomenaWeb.Topic.Post.DeleteController do end end - defp log_details(conn, _action, post) do + defp log_details(_conn, _action, post) do %{ body: "Destroyed forum post ##{post.id} in topic '#{post.topic.title}'", subject_path: diff --git a/lib/philomena_web/controllers/topic/post/hide_controller.ex b/lib/philomena_web/controllers/topic/post/hide_controller.ex index ed3f69d9..da423f3b 100644 --- a/lib/philomena_web/controllers/topic/post/hide_controller.ex +++ b/lib/philomena_web/controllers/topic/post/hide_controller.ex @@ -63,7 +63,7 @@ defmodule PhilomenaWeb.Topic.Post.HideController do end end - defp log_details(conn, action, post) do + defp log_details(_conn, action, post) do body = case action do :create -> diff --git a/lib/philomena_web/controllers/topic/stick_controller.ex b/lib/philomena_web/controllers/topic/stick_controller.ex index d413be6d..a6ee72c4 100644 --- a/lib/philomena_web/controllers/topic/stick_controller.ex +++ b/lib/philomena_web/controllers/topic/stick_controller.ex @@ -52,7 +52,7 @@ defmodule PhilomenaWeb.Topic.StickController do end end - defp log_details(conn, action, topic) do + defp log_details(_conn, action, topic) do body = case action do :create -> "Stickied topic '#{topic.title}' in #{topic.forum.name}" From e69f1bf3fa1dd33f0ff71bea1b3732de47fd87f8 Mon Sep 17 00:00:00 2001 From: Liam Date: Sun, 28 Apr 2024 21:04:28 -0400 Subject: [PATCH 08/35] Fixup --- lib/philomena_web/controllers/admin/batch/tag_controller.ex | 2 +- lib/philomena_web/controllers/image/tamper_controller.ex | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/philomena_web/controllers/admin/batch/tag_controller.ex b/lib/philomena_web/controllers/admin/batch/tag_controller.ex index 512a0972..59371b6a 100644 --- a/lib/philomena_web/controllers/admin/batch/tag_controller.ex +++ b/lib/philomena_web/controllers/admin/batch/tag_controller.ex @@ -68,7 +68,7 @@ defmodule PhilomenaWeb.Admin.Batch.TagController do end end - defp log_details(_conn, _action, data) do + defp log_details(conn, _action, data) do %{ body: "Batch tagged '#{data.tag_list}' on #{data.image_count} images", subject_path: ~p"/profiles/#{conn.assigns.current_user}" diff --git a/lib/philomena_web/controllers/image/tamper_controller.ex b/lib/philomena_web/controllers/image/tamper_controller.ex index 482bb14a..4ce1ac3c 100644 --- a/lib/philomena_web/controllers/image/tamper_controller.ex +++ b/lib/philomena_web/controllers/image/tamper_controller.ex @@ -31,7 +31,7 @@ defmodule PhilomenaWeb.Image.TamperController do |> redirect(to: ~p"/images/#{conn.assigns.image}") end - defp log_details(_conn, _action, data) do + defp log_details(conn, _action, data) do image = data.image vote_type = From c506ef884e759d6cfb787da7c65cf47179b67a45 Mon Sep 17 00:00:00 2001 From: Liam Date: Sun, 28 Apr 2024 21:08:00 -0400 Subject: [PATCH 09/35] link_to_reported_thing, link_to_noted_thing --- .../templates/admin/mod_note/_table.html.slime | 2 +- .../templates/admin/report/_reports.html.slime | 2 +- .../templates/admin/report/show.html.slime | 2 +- .../templates/report/index.html.slime | 2 +- .../templates/report/new.html.slime | 2 +- lib/philomena_web/views/admin/mod_note_view.ex | 10 +++++----- lib/philomena_web/views/admin/report_view.ex | 4 ++-- lib/philomena_web/views/report_view.ex | 16 ++++++++-------- 8 files changed, 20 insertions(+), 20 deletions(-) diff --git a/lib/philomena_web/templates/admin/mod_note/_table.html.slime b/lib/philomena_web/templates/admin/mod_note/_table.html.slime index 6c143079..45207800 100644 --- a/lib/philomena_web/templates/admin/mod_note/_table.html.slime +++ b/lib/philomena_web/templates/admin/mod_note/_table.html.slime @@ -10,7 +10,7 @@ table.table = for {body, note} <- @mod_notes do tr td - = link_to_noted_thing(@conn, note.notable) + = link_to_noted_thing(note.notable) td = body diff --git a/lib/philomena_web/templates/admin/report/_reports.html.slime b/lib/philomena_web/templates/admin/report/_reports.html.slime index 743f51cb..9ac6563e 100644 --- a/lib/philomena_web/templates/admin/report/_reports.html.slime +++ b/lib/philomena_web/templates/admin/report/_reports.html.slime @@ -12,7 +12,7 @@ table.table tr td => reported_image @conn, report.reportable - = link_to_reported_thing @conn, report.reportable + = link_to_reported_thing report.reportable td span title=report.reason = truncate(report.reason) diff --git a/lib/philomena_web/templates/admin/report/show.html.slime b/lib/philomena_web/templates/admin/report/show.html.slime index d0d183a8..20835cdd 100644 --- a/lib/philomena_web/templates/admin/report/show.html.slime +++ b/lib/philomena_web/templates/admin/report/show.html.slime @@ -1,6 +1,6 @@ h1 Showing Report p - = link_to_reported_thing @conn, @report.reportable + = link_to_reported_thing @report.reportable article.block.communication .block__content.flex.flex--no-wrap diff --git a/lib/philomena_web/templates/report/index.html.slime b/lib/philomena_web/templates/report/index.html.slime index a7e35224..2d7d6563 100644 --- a/lib/philomena_web/templates/report/index.html.slime +++ b/lib/philomena_web/templates/report/index.html.slime @@ -18,6 +18,6 @@ h1 Your Reports tr td class=report_row_class(r) = pretty_state(r) - td = link_to_reported_thing(@conn, r.reportable) + td = link_to_reported_thing(r.reportable) td = r.reason td = pretty_time(r.created_at) diff --git a/lib/philomena_web/templates/report/new.html.slime b/lib/philomena_web/templates/report/new.html.slime index 15f2a32a..f7839783 100644 --- a/lib/philomena_web/templates/report/new.html.slime +++ b/lib/philomena_web/templates/report/new.html.slime @@ -1,7 +1,7 @@ h2 Submit a report p strong - = link_to_reported_thing(@conn, @reportable) + = link_to_reported_thing(@reportable) .image-other .dnp-warning diff --git a/lib/philomena_web/views/admin/mod_note_view.ex b/lib/philomena_web/views/admin/mod_note_view.ex index 463de66b..021e4721 100644 --- a/lib/philomena_web/views/admin/mod_note_view.ex +++ b/lib/philomena_web/views/admin/mod_note_view.ex @@ -5,20 +5,20 @@ defmodule PhilomenaWeb.Admin.ModNoteView do alias Philomena.Reports.Report alias Philomena.DnpEntries.DnpEntry - def link_to_noted_thing(conn, %DnpEntry{tag: tag} = dnp_entry), + def link_to_noted_thing(%DnpEntry{tag: tag} = dnp_entry), do: link("DNP entry for #{tag.name}", to: ~p"/dnp/#{dnp_entry}") - def link_to_noted_thing(conn, %Report{user: nil} = report), + def link_to_noted_thing(%Report{user: nil} = report), do: link("Report #{report.id}", to: ~p"/admin/reports/#{report}") - def link_to_noted_thing(conn, %Report{user: user} = report), + def link_to_noted_thing(%Report{user: user} = report), do: link("Report #{report.id} by #{user.name}", to: ~p"/admin/reports/#{report}" ) - def link_to_noted_thing(conn, %User{} = user), + def link_to_noted_thing(%User{} = user), do: link("User #{user.name}", to: ~p"/profiles/#{user}") - def link_to_noted_thing(_conn, _notable), do: "Item permanently deleted" + def link_to_noted_thing(_notable), do: "Item permanently deleted" end diff --git a/lib/philomena_web/views/admin/report_view.ex b/lib/philomena_web/views/admin/report_view.ex index a192c4fd..56337cd2 100644 --- a/lib/philomena_web/views/admin/report_view.ex +++ b/lib/philomena_web/views/admin/report_view.ex @@ -7,8 +7,8 @@ defmodule PhilomenaWeb.Admin.ReportView do alias PhilomenaWeb.ReportView alias PhilomenaWeb.ProfileView - defp link_to_reported_thing(conn, reportable), - do: ReportView.link_to_reported_thing(conn, reportable) + defp link_to_reported_thing(reportable), + do: ReportView.link_to_reported_thing(reportable) defp report_row_class(report), do: ReportView.report_row_class(report) diff --git a/lib/philomena_web/views/report_view.ex b/lib/philomena_web/views/report_view.ex index e33493be..35693434 100644 --- a/lib/philomena_web/views/report_view.ex +++ b/lib/philomena_web/views/report_view.ex @@ -41,31 +41,31 @@ defmodule PhilomenaWeb.ReportView do def pretty_state(%{state: "claimed"}), do: "Claimed" def pretty_state(_report), do: "Open" - def link_to_reported_thing(conn, %Image{} = r), + def link_to_reported_thing(%Image{} = r), do: link("Image >>#{r.id}", to: ~p"/images/#{r}") - def link_to_reported_thing(conn, %Comment{} = r), + def link_to_reported_thing(%Comment{} = r), do: link("Comment on image >>#{r.image.id}", to: ~p"/images/#{r.image}" <> "#comment_#{r.id}" ) - def link_to_reported_thing(conn, %Conversation{} = r), + def link_to_reported_thing(%Conversation{} = r), do: link("Conversation between #{r.from.name} and #{r.to.name}", to: ~p"/conversations/#{r}" ) - def link_to_reported_thing(conn, %Commission{} = r), + def link_to_reported_thing(%Commission{} = r), do: link("#{r.user.name}'s commission page", to: ~p"/profiles/#{r.user}/commission" ) - def link_to_reported_thing(conn, %Gallery{} = r), + def link_to_reported_thing(%Gallery{} = r), do: link("Gallery '#{r.title}' by #{r.creator.name}", to: ~p"/galleries/#{r}") - def link_to_reported_thing(conn, %Post{} = r), + def link_to_reported_thing(%Post{} = r), do: link("Post in #{r.topic.title}", to: @@ -73,10 +73,10 @@ defmodule PhilomenaWeb.ReportView do "#post_#{r.id}" ) - def link_to_reported_thing(conn, %User{} = r), + def link_to_reported_thing(%User{} = r), do: link("User '#{r.name}'", to: ~p"/profiles/#{r}") - def link_to_reported_thing(_conn, _reportable) do + def link_to_reported_thing(_reportable) do "Reported item permanently destroyed." end end From 42039491b63e5e674324c62647eab928073f44b7 Mon Sep 17 00:00:00 2001 From: Liam Date: Sun, 28 Apr 2024 21:11:56 -0400 Subject: [PATCH 10/35] redirect_path, user_abbrv, last_message_path --- lib/philomena_web/controllers/report_controller.ex | 6 +++--- .../templates/admin/fingerprint_ban/index.html.slime | 2 +- .../templates/admin/report/_reports.html.slime | 2 +- .../templates/admin/subnet_ban/index.html.slime | 2 +- lib/philomena_web/templates/admin/user_ban/index.html.slime | 2 +- lib/philomena_web/templates/conversation/index.html.slime | 2 +- lib/philomena_web/templates/profile/show.html.slime | 2 +- lib/philomena_web/views/admin/ban_view.ex | 4 ++-- lib/philomena_web/views/admin/report_view.ex | 4 ++-- lib/philomena_web/views/conversation_view.ex | 2 +- lib/philomena_web/views/profile_view.ex | 4 ++-- 11 files changed, 16 insertions(+), 16 deletions(-) diff --git a/lib/philomena_web/controllers/report_controller.ex b/lib/philomena_web/controllers/report_controller.ex index 930ecf13..7860a32e 100644 --- a/lib/philomena_web/controllers/report_controller.ex +++ b/lib/philomena_web/controllers/report_controller.ex @@ -53,7 +53,7 @@ defmodule PhilomenaWeb.ReportController do :info, "Your report has been received and will be checked by staff shortly." ) - |> redirect(to: redirect_path(conn, conn.assigns.current_user)) + |> redirect(to: redirect_path(conn.assigns.current_user)) {:error, changeset} -> # Note that we are depending on the controller that called @@ -100,8 +100,8 @@ defmodule PhilomenaWeb.ReportController do reports_open >= max_reports() end - defp redirect_path(_conn, nil), do: "/" - defp redirect_path(conn, _user), do: ~p"/reports" + defp redirect_path(nil), do: "/" + defp redirect_path(_user), do: ~p"/reports" defp max_reports do 5 diff --git a/lib/philomena_web/templates/admin/fingerprint_ban/index.html.slime b/lib/philomena_web/templates/admin/fingerprint_ban/index.html.slime index 209ad509..7e42314a 100644 --- a/lib/philomena_web/templates/admin/fingerprint_ban/index.html.slime +++ b/lib/philomena_web/templates/admin/fingerprint_ban/index.html.slime @@ -35,7 +35,7 @@ h1 Fingerprint Bans td => pretty_time ban.created_at - = user_abbrv @conn, ban.banning_user + = user_abbrv ban.banning_user td class=ban_row_class(ban) = pretty_time ban.valid_until diff --git a/lib/philomena_web/templates/admin/report/_reports.html.slime b/lib/philomena_web/templates/admin/report/_reports.html.slime index 9ac6563e..a423d1e7 100644 --- a/lib/philomena_web/templates/admin/report/_reports.html.slime +++ b/lib/philomena_web/templates/admin/report/_reports.html.slime @@ -32,7 +32,7 @@ table.table td class=report_row_class(report) => pretty_state(report) - = user_abbrv @conn, report.admin + = user_abbrv report.admin td => link "Show", to: ~p"/admin/reports/#{report}" diff --git a/lib/philomena_web/templates/admin/subnet_ban/index.html.slime b/lib/philomena_web/templates/admin/subnet_ban/index.html.slime index ff139197..c051a10a 100644 --- a/lib/philomena_web/templates/admin/subnet_ban/index.html.slime +++ b/lib/philomena_web/templates/admin/subnet_ban/index.html.slime @@ -35,7 +35,7 @@ h1 Subnet Bans td => pretty_time ban.created_at - = user_abbrv @conn, ban.banning_user + = user_abbrv ban.banning_user td class=ban_row_class(ban) = pretty_time ban.valid_until diff --git a/lib/philomena_web/templates/admin/user_ban/index.html.slime b/lib/philomena_web/templates/admin/user_ban/index.html.slime index 3f76034d..5b60fc21 100644 --- a/lib/philomena_web/templates/admin/user_ban/index.html.slime +++ b/lib/philomena_web/templates/admin/user_ban/index.html.slime @@ -35,7 +35,7 @@ h1 User Bans td => pretty_time ban.created_at - = user_abbrv @conn, ban.banning_user + = user_abbrv ban.banning_user td class=ban_row_class(ban) = pretty_time ban.valid_until diff --git a/lib/philomena_web/templates/conversation/index.html.slime b/lib/philomena_web/templates/conversation/index.html.slime index ea476547..611610e0 100644 --- a/lib/philomena_web/templates/conversation/index.html.slime +++ b/lib/philomena_web/templates/conversation/index.html.slime @@ -36,7 +36,7 @@ h1 My Conversations td.table--communication-list__stats = render PhilomenaWeb.UserAttributionView, "_user.html", object: %{user: other_party(@current_user, c)}, conn: @conn td.table--communication-list__options - => link "Last message", to: last_message_path(@conn, c, count) + => link "Last message", to: last_message_path(c, count) ' • => link "Hide", to: ~p"/conversations/#{c}/hide", data: [method: "post"], data: [confirm: "Are you really, really sure?"] diff --git a/lib/philomena_web/templates/profile/show.html.slime b/lib/philomena_web/templates/profile/show.html.slime index 3179e247..6039a48d 100644 --- a/lib/philomena_web/templates/profile/show.html.slime +++ b/lib/philomena_web/templates/profile/show.html.slime @@ -116,7 +116,7 @@ .flex__grow.center => pretty_time(award.awarded_on) = if manages_awards?(@conn) do - = user_abbrv(@conn, award.awarded_by) + = user_abbrv(award.awarded_by) = if manages_awards?(@conn) do .flex__grow.center diff --git a/lib/philomena_web/views/admin/ban_view.ex b/lib/philomena_web/views/admin/ban_view.ex index 0df1e730..59fbe1de 100644 --- a/lib/philomena_web/views/admin/ban_view.ex +++ b/lib/philomena_web/views/admin/ban_view.ex @@ -1,8 +1,8 @@ defmodule PhilomenaWeb.Admin.BanView do alias PhilomenaWeb.ProfileView - def user_abbrv(conn, user), - do: ProfileView.user_abbrv(conn, user) + def user_abbrv(user), + do: ProfileView.user_abbrv(user) def ban_row_class(%{valid_until: until, enabled: enabled}) do now = DateTime.utc_now() diff --git a/lib/philomena_web/views/admin/report_view.ex b/lib/philomena_web/views/admin/report_view.ex index 56337cd2..7f81d93d 100644 --- a/lib/philomena_web/views/admin/report_view.ex +++ b/lib/philomena_web/views/admin/report_view.ex @@ -16,8 +16,8 @@ defmodule PhilomenaWeb.Admin.ReportView do defp pretty_state(report), do: ReportView.pretty_state(report) - defp user_abbrv(conn, user), - do: ProfileView.user_abbrv(conn, user) + defp user_abbrv(user), + do: ProfileView.user_abbrv(user) defp current?(current_user, user), do: ProfileView.current?(current_user, user) diff --git a/lib/philomena_web/views/conversation_view.ex b/lib/philomena_web/views/conversation_view.ex index c85902ab..97ce9c99 100644 --- a/lib/philomena_web/views/conversation_view.ex +++ b/lib/philomena_web/views/conversation_view.ex @@ -32,7 +32,7 @@ defmodule PhilomenaWeb.ConversationView do end end - def last_message_path(conn, conversation, count) do + def last_message_path(conversation, count) do page = trunc(Float.ceil(count / 25)) ~p"/conversations/#{conversation}?#{[page: page]}" diff --git a/lib/philomena_web/views/profile_view.ex b/lib/philomena_web/views/profile_view.ex index 2470d5cf..916ba334 100644 --- a/lib/philomena_web/views/profile_view.ex +++ b/lib/philomena_web/views/profile_view.ex @@ -77,7 +77,7 @@ defmodule PhilomenaWeb.ProfileView do def enabled_text(true), do: "Enabled" def enabled_text(_else), do: "Disabled" - def user_abbrv(conn, %{name: name} = user) do + def user_abbrv(%{name: name} = user) do abbrv = String.upcase(initials_abbrv(name) || uppercase_abbrv(name) || first_letters_abbrv(name)) @@ -86,7 +86,7 @@ defmodule PhilomenaWeb.ProfileView do link(abbrv, to: ~p"/profiles/#{user}") end - def user_abbrv(_conn, _user), do: content_tag(:span, "(n/a)") + def user_abbrv(_user), do: content_tag(:span, "(n/a)") defp initials_abbrv(name) do case String.split(name, " ", parts: 4) do From 9ba670c864e2959e5c256f7dbe01fd3b14ff725f Mon Sep 17 00:00:00 2001 From: Liam Date: Sun, 28 Apr 2024 21:13:51 -0400 Subject: [PATCH 11/35] truncated_ip_link --- .../templates/admin/approval/_approvals.html.slime | 2 +- lib/philomena_web/templates/admin/report/_reports.html.slime | 2 +- lib/philomena_web/views/admin/approval_view.ex | 3 +-- lib/philomena_web/views/admin/report_view.ex | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/philomena_web/templates/admin/approval/_approvals.html.slime b/lib/philomena_web/templates/admin/approval/_approvals.html.slime index f0448000..d3d3f5fc 100644 --- a/lib/philomena_web/templates/admin/approval/_approvals.html.slime +++ b/lib/philomena_web/templates/admin/approval/_approvals.html.slime @@ -21,7 +21,7 @@ = link image.user.name, to: ~p"/profiles/#{image.user}" - else em> - = truncated_ip_link(@conn, image.ip) + = truncated_ip_link(image.ip) = link_to_fingerprint(@conn, image.fingerprint) span = pretty_time(image.created_at) .approval-items--footer diff --git a/lib/philomena_web/templates/admin/report/_reports.html.slime b/lib/philomena_web/templates/admin/report/_reports.html.slime index a423d1e7..30b4ad36 100644 --- a/lib/philomena_web/templates/admin/report/_reports.html.slime +++ b/lib/philomena_web/templates/admin/report/_reports.html.slime @@ -21,7 +21,7 @@ table.table = link report.user.name, to: ~p"/profiles/#{report.user}" - else em> - = truncated_ip_link(@conn, report.ip) + = truncated_ip_link(report.ip) = link_to_fingerprint(@conn, report.fingerprint) = if not is_nil(report.user) and Enum.any?(report.user.linked_tags) do diff --git a/lib/philomena_web/views/admin/approval_view.ex b/lib/philomena_web/views/admin/approval_view.ex index 03b0f3c2..12d6284b 100644 --- a/lib/philomena_web/views/admin/approval_view.ex +++ b/lib/philomena_web/views/admin/approval_view.ex @@ -3,8 +3,7 @@ defmodule PhilomenaWeb.Admin.ApprovalView do alias PhilomenaWeb.Admin.ReportView - # Shamelessly copied from ReportView - def truncated_ip_link(conn, ip), do: ReportView.truncated_ip_link(conn, ip) + def truncated_ip_link(ip), do: ReportView.truncated_ip_link(ip) def image_thumb(conn, image) do render(PhilomenaWeb.ImageView, "_image_container.html", diff --git a/lib/philomena_web/views/admin/report_view.ex b/lib/philomena_web/views/admin/report_view.ex index 7f81d93d..82de807d 100644 --- a/lib/philomena_web/views/admin/report_view.ex +++ b/lib/philomena_web/views/admin/report_view.ex @@ -25,7 +25,7 @@ defmodule PhilomenaWeb.Admin.ReportView do def truncate(<>), do: string <> "..." def truncate(string), do: string - def truncated_ip_link(conn, ip) do + def truncated_ip_link(ip) do case to_string(ip) do <> = ip -> link(string <> "...", to: ~p"/ip_profiles/#{ip}") From d9b3fe4fc8e6f350d8056d1b8f1eab71a874f404 Mon Sep 17 00:00:00 2001 From: Liam Date: Sun, 28 Apr 2024 21:18:59 -0400 Subject: [PATCH 12/35] Remove old route helpers --- lib/philomena_web.ex | 2 -- lib/philomena_web/plugs/tor_plug.ex | 1 - lib/philomena_web/plugs/totp_plug.ex | 1 - lib/philomena_web/user_auth.ex | 1 - test/support/conn_case.ex | 1 - 5 files changed, 6 deletions(-) diff --git a/lib/philomena_web.ex b/lib/philomena_web.ex index f7234480..a4bccdf2 100644 --- a/lib/philomena_web.ex +++ b/lib/philomena_web.ex @@ -27,7 +27,6 @@ defmodule PhilomenaWeb do import PhilomenaWeb.Gettext import Canary.Plugs import PhilomenaWeb.ModerationLogPlug, only: [moderation_log: 2] - alias PhilomenaWeb.Router.Helpers, as: Routes unquote(verified_routes()) end @@ -47,7 +46,6 @@ defmodule PhilomenaWeb do import PhilomenaWeb.ErrorHelpers import PhilomenaWeb.Gettext - alias PhilomenaWeb.Router.Helpers, as: Routes # Wrong way around for convenience import PhilomenaWeb.AppView diff --git a/lib/philomena_web/plugs/tor_plug.ex b/lib/philomena_web/plugs/tor_plug.ex index bea6b9d2..57d5745a 100644 --- a/lib/philomena_web/plugs/tor_plug.ex +++ b/lib/philomena_web/plugs/tor_plug.ex @@ -6,7 +6,6 @@ defmodule PhilomenaWeb.TorPlug do plug PhilomenaWeb.TorPlug """ - alias PhilomenaWeb.Router.Helpers, as: Routes use PhilomenaWeb, :verified_routes alias Phoenix.Controller diff --git a/lib/philomena_web/plugs/totp_plug.ex b/lib/philomena_web/plugs/totp_plug.ex index 6b809123..7f5e2d11 100644 --- a/lib/philomena_web/plugs/totp_plug.ex +++ b/lib/philomena_web/plugs/totp_plug.ex @@ -7,7 +7,6 @@ defmodule PhilomenaWeb.TotpPlug do plug PhilomenaWeb.TotpPlug """ - alias PhilomenaWeb.Router.Helpers, as: Routes use PhilomenaWeb, :verified_routes @doc false diff --git a/lib/philomena_web/user_auth.ex b/lib/philomena_web/user_auth.ex index bf45d8b6..3665997c 100644 --- a/lib/philomena_web/user_auth.ex +++ b/lib/philomena_web/user_auth.ex @@ -3,7 +3,6 @@ defmodule PhilomenaWeb.UserAuth do import Phoenix.Controller alias Philomena.Users - alias PhilomenaWeb.Router.Helpers, as: Routes alias PhilomenaWeb.UserIpUpdater alias PhilomenaWeb.UserFingerprintUpdater diff --git a/test/support/conn_case.ex b/test/support/conn_case.ex index 151ed056..aa9df751 100644 --- a/test/support/conn_case.ex +++ b/test/support/conn_case.ex @@ -21,7 +21,6 @@ defmodule PhilomenaWeb.ConnCase do import Plug.Conn import Phoenix.ConnTest import PhilomenaWeb.ConnCase - alias PhilomenaWeb.Router.Helpers, as: Routes # The default endpoint for testing @endpoint PhilomenaWeb.Endpoint From 9e79648e4450f2391b00fcc43fd75abf161ff4f3 Mon Sep 17 00:00:00 2001 From: Liam Date: Sun, 28 Apr 2024 21:30:14 -0400 Subject: [PATCH 13/35] Remove converter --- lib/mix/tasks/convert_to_verified_routes.ex | 233 -------------------- 1 file changed, 233 deletions(-) delete mode 100644 lib/mix/tasks/convert_to_verified_routes.ex diff --git a/lib/mix/tasks/convert_to_verified_routes.ex b/lib/mix/tasks/convert_to_verified_routes.ex deleted file mode 100644 index ad643d2b..00000000 --- a/lib/mix/tasks/convert_to_verified_routes.ex +++ /dev/null @@ -1,233 +0,0 @@ -defmodule Mix.Tasks.ConvertToVerifiedRoutes do - @moduledoc """ - Replaces routes with verified routes. - Forked from - https://gist.github.com/andreaseriksson/e454b9244a734310d4ab74d8595f98cd - https://gist.github.com/jiegillet/e6357c82e36a848ad59295eb3d5a1135 - - This requires all routes to consistently be aliased with - alias PhilomenaWeb.Router.Helpers, as: Routes - - Run with - mix convert_to_verified_routes - """ - - use Mix.Task - - @regex ~r/(Routes\.)([a-zA-Z0-9_]+)(path|url)\(/ - @web_module PhilomenaWeb - - def run(_) do - Path.wildcard("test/**/*.ex*") - |> Enum.concat(Path.wildcard("lib/**/*.ex*")) - |> Enum.concat(Path.wildcard("lib/**/*.eex*")) - |> Enum.concat(Path.wildcard("lib/**/*.slime")) - |> Enum.sort() - |> Enum.reject(&String.contains?(&1, "convert_to_verified_routes.ex")) - |> Enum.filter(&(&1 |> File.read!() |> String.contains?("Routes."))) - |> Enum.each(&format_file/1) - - :ok - end - - def format_file(filename) do - Mix.shell().info(filename) - - formatted_content = - filename - |> File.read!() - |> format_string() - - File.write!(filename, [formatted_content]) - end - - def format_string(source) do - case Regex.run(@regex, source, capture: :first, return: :index) do - [{index, length}] -> - # Compute full length of expression - length = nibble_expression(source, index, length) - - # Convert to verified route format - route = format_route(String.slice(source, index, length)) - - # Split string around expression - prefix = String.slice(source, 0, index) - suffix = String.slice(source, index + length, String.length(source)) - - # Insert verified route and rerun - format_string("#{prefix}#{route}#{suffix}") - - _ -> - source - end - end - - defp nibble_expression(source, index, length) do - if index + length > String.length(source) do - raise "Failed to match route expression" - end - - case Code.string_to_quoted(String.slice(source, index, length)) do - {:ok, _macro} -> - length - - _ -> - nibble_expression(source, index, length + 1) - end - end - - defp format_route(route) do - ast = - Code.string_to_quoted!(route, - literal_encoder: &{:ok, {:__block__, &2, [&1]}}, - unescape: false, - token_metadata: true - ) - - ast - |> Macro.prewalk(&replace_route/1) - |> Code.quoted_to_algebra(escape: false) - |> Inspect.Algebra.format(:infinity) - end - - defp decode_literal(literal) when is_binary(literal) or is_integer(literal) do - {:ok, literal} - end - - defp decode_literal({:__block__, _, [literal]}) do - {:ok, literal} - end - - defp decode_literal(node), do: {:error, node} - - defp encode_literal(literal) do - {:__block__, [], [literal]} - end - - # Routes.url(MyAppWeb.Endpoint) - defp replace_route({{:., _, [{:__aliases__, _, [:Routes]}, :url]}, _, [_conn_or_endpoint]}) do - {:url, [], [{:sigil_p, [delimiter: "\""], [{:<<>>, [], ["/"]}, []]}]} - end - - # Routes.static_path(conn, "/images/favicon.ico") - defp replace_route({{:., _, [{:__aliases__, _, [:Routes]}, :static_path]}, _, args}) do - [_conn_or_endpoint, path] = args - - case decode_literal(path) do - {:ok, path} -> {:sigil_p, [delimiter: "\""], [{:<<>>, [], [path]}, []]} - _ -> {:sigil_p, [delimiter: "\""], [path, []]} - end - end - - # Routes.static_url(conn, "/images/favicon.ico") - defp replace_route({{:., _, [{:__aliases__, _, [:Routes]}, :static_url]}, _, args}) do - [_conn_or_endpoint, path] = args - - sigil = - case decode_literal(path) do - {:ok, path} -> {:sigil_p, [delimiter: "\""], [{:<<>>, [], [path]}, []]} - _ -> {:sigil_p, [delimiter: "\""], [path, []]} - end - - {:url, [], [sigil]} - end - - # Routes.some_path(conn, :action, "en", query_params) - defp replace_route( - {{:., _, [{:__aliases__, _, [:Routes]}, path_name]}, _, [_ | _] = args} = node - ) do - [_conn_or_endpoint, action | params] = args - - action = - case decode_literal(action) do - {:ok, action} -> action - _ -> action - end - - path_name = "#{path_name}" - - case find_verified_route(path_name, action, params) do - :ok -> node - route -> route - end - end - - defp replace_route(node), do: node - - defp find_verified_route(path_name, action, arguments) do - # pleaaaase don't have a route named Routes.product_url_path(conn, :index) - trimmed_path = path_name |> String.trim_trailing("_path") |> String.trim_trailing("_url") - - route = - Phoenix.Router.routes(@web_module.Router) - |> Enum.find(fn %{helper: helper, plug_opts: plug_opts} -> - plug_opts == action && is_binary(helper) && trimmed_path == helper - end) - - case route do - %{path: path} -> - {path_bits, query_params} = - path - |> String.split("/", trim: true) - |> replace_path_variables(arguments, []) - - path_bits = - path_bits - |> Enum.flat_map(fn bit -> ["/", bit] end) - |> format_for_sigil_binary_args(query_params) - - sigil = {:sigil_p, [delimiter: "\""], [{:<<>>, [], path_bits}, []]} - - if String.ends_with?(path_name, "_url") do - {:url, [], [sigil]} - else - sigil - end - - _ -> - Mix.shell().error( - "Could not find route #{path_name}, with action #{inspect(action)} and arguments #{inspect(arguments)}" - ) - end - end - - defp replace_path_variables([], arguments, path_bits) do - {Enum.reverse(path_bits), arguments} - end - - defp replace_path_variables(path, [], path_bits) do - {Enum.reverse(path_bits) ++ path, []} - end - - # conceptually /post/:post_id -> /post/#{id} - defp replace_path_variables([path_piece | rest], [arg | args], path_bits) do - if String.starts_with?(path_piece, ":") do - replace_path_variables(rest, args, [arg | path_bits]) - else - replace_path_variables(rest, [arg | args], [path_piece | path_bits]) - end - end - - defp format_for_sigil_binary_args(path_bits, [_ | _] = query_params) do - format_for_sigil_binary_args(path_bits ++ ["?" | query_params], []) - end - - defp format_for_sigil_binary_args(path_bits, []) do - path_bits - |> Enum.map(&decode_literal/1) - |> Enum.map(fn - {:ok, bit} when is_binary(bit) -> - bit - - {:ok, bit} when is_atom(bit) or is_integer(bit) -> - to_string(bit) - - {_, bit} -> - {:"::", [], - [ - {{:., [], [Kernel, :to_string]}, [from_interpolation: true], [encode_literal(bit)]}, - {:binary, [], Elixir} - ]} - end) - end -end From 9d20b9c4655335b759595e8f6ce34c00062b9653 Mon Sep 17 00:00:00 2001 From: Liam Date: Sat, 1 Jun 2024 23:34:38 -0400 Subject: [PATCH 14/35] Ensure flash is fetched before putting flash --- lib/philomena_web/user_auth.ex | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/philomena_web/user_auth.ex b/lib/philomena_web/user_auth.ex index 84b79a70..b4fa3f8a 100644 --- a/lib/philomena_web/user_auth.ex +++ b/lib/philomena_web/user_auth.ex @@ -192,6 +192,7 @@ defmodule PhilomenaWeb.UserAuth do conn else conn + |> fetch_flash() |> put_flash(:error, "You must log in to access this page.") |> maybe_store_return_to() |> redirect(to: Routes.session_path(conn, :new)) From 80f9fa9352b1b98930b03d7c46de87fc47352e54 Mon Sep 17 00:00:00 2001 From: liamwhite Date: Sat, 1 Jun 2024 23:35:19 -0400 Subject: [PATCH 15/35] Fix Dialyzer (#265) * Fix post-Elixir 1.16 divergence in File.stream! * Add exclusion for PhilomenaWeb.Config compile-time variance * Add missing Autocomplete.t --- lib/philomena/autocomplete/autocomplete.ex | 2 ++ lib/philomena/sha512.ex | 22 +++++++++++++++++++--- lib/philomena_web/config.ex | 4 ++++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/lib/philomena/autocomplete/autocomplete.ex b/lib/philomena/autocomplete/autocomplete.ex index ed7dc5fa..6be4dcf2 100644 --- a/lib/philomena/autocomplete/autocomplete.ex +++ b/lib/philomena/autocomplete/autocomplete.ex @@ -2,6 +2,8 @@ defmodule Philomena.Autocomplete.Autocomplete do use Ecto.Schema import Ecto.Changeset + @type t :: %__MODULE__{} + @primary_key false schema "autocomplete" do field :content, :binary diff --git a/lib/philomena/sha512.ex b/lib/philomena/sha512.ex index 1b500440..03c9645e 100644 --- a/lib/philomena/sha512.ex +++ b/lib/philomena/sha512.ex @@ -1,11 +1,27 @@ defmodule Philomena.Sha512 do - @spec file(String.t()) :: String.t() - def file(file) do + @chunk_size 10_485_760 + + @spec file(Path.t()) :: String.t() + def file(path) do hash_ref = :crypto.hash_init(:sha512) - File.stream!(file, [], 10_485_760) + path + |> stream_file() |> Enum.reduce(hash_ref, &:crypto.hash_update(&2, &1)) |> :crypto.hash_final() |> Base.encode16(case: :lower) end + + if Version.match?(System.version(), ">= 1.16.0") do + # `stream!/2` was added in Elixir 1.16 to accept a shortened form, + # where we only need to specify the size of each stream chunk + defp stream_file(file) do + File.stream!(file, @chunk_size) + end + else + # Use legacy stream/3 for older Elixir versions + defp stream_file(file) do + File.stream!(file, [], @chunk_size) + end + end end diff --git a/lib/philomena_web/config.ex b/lib/philomena_web/config.ex index c661550e..7061ef26 100644 --- a/lib/philomena_web/config.ex +++ b/lib/philomena_web/config.ex @@ -1,4 +1,8 @@ defmodule PhilomenaWeb.Config do + # Dialyzer only analyzes beam files directly and cannot see the compile-time variance in + # the associated values, so it flags a false positive here. + @dialyzer [:no_match] + @reload_enabled Application.compile_env(:philomena, :vite_reload, false) @csp_relaxed Application.compile_env(:philomena, :csp_relaxed, false) From e6c7651d5d1435ec44c669d6a3149c796337d6c6 Mon Sep 17 00:00:00 2001 From: liamwhite Date: Sat, 1 Jun 2024 23:37:39 -0400 Subject: [PATCH 16/35] Fix MFA usage in cast_assoc (#267) --- lib/philomena/conversations/conversation.ex | 2 +- lib/philomena/topics/topic.ex | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/philomena/conversations/conversation.ex b/lib/philomena/conversations/conversation.ex index 07e3f4ab..ac188f1d 100644 --- a/lib/philomena/conversations/conversation.ex +++ b/lib/philomena/conversations/conversation.ex @@ -57,7 +57,7 @@ defmodule Philomena.Conversations.Conversation do |> put_recipient() |> set_slug() |> set_last_message() - |> cast_assoc(:messages, with: {Message, :creation_changeset, [from]}) + |> cast_assoc(:messages, with: &Message.creation_changeset(&1, &2, from)) |> validate_length(:messages, is: 1) end diff --git a/lib/philomena/topics/topic.ex b/lib/philomena/topics/topic.ex index efc49ce4..0db30126 100644 --- a/lib/philomena/topics/topic.ex +++ b/lib/philomena/topics/topic.ex @@ -59,7 +59,7 @@ defmodule Philomena.Topics.Topic do |> change(forum: forum, user: attribution[:user]) |> validate_required(:forum) |> cast_assoc(:poll, with: &Poll.update_changeset/2) - |> cast_assoc(:posts, with: {Post, :topic_creation_changeset, [attribution, anonymous?]}) + |> cast_assoc(:posts, with: &Post.topic_creation_changeset(&1, &2, attribution, anonymous?)) |> validate_length(:posts, is: 1) |> unique_constraint(:slug, name: :index_topics_on_forum_id_and_slug) end From 7667aec1458d0558a7f59097642907e7f082f2c2 Mon Sep 17 00:00:00 2001 From: Liam Date: Sun, 2 Jun 2024 00:02:37 -0400 Subject: [PATCH 17/35] Fix invalid backwards range usage with String.slice --- lib/philomena_web/controllers/admin/batch/tag_controller.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/philomena_web/controllers/admin/batch/tag_controller.ex b/lib/philomena_web/controllers/admin/batch/tag_controller.ex index 59371b6a..302981be 100644 --- a/lib/philomena_web/controllers/admin/batch/tag_controller.ex +++ b/lib/philomena_web/controllers/admin/batch/tag_controller.ex @@ -17,7 +17,7 @@ defmodule PhilomenaWeb.Admin.Batch.TagController do removed_tag_names = tags |> Enum.filter(&String.starts_with?(&1, "-")) - |> Enum.map(&String.slice(&1, 1..-1)) + |> Enum.map(&String.replace_leading(&1, "-", "")) added_tags = Tag From a95df5ec4200490381f866b230c7cbe4dd56c3aa Mon Sep 17 00:00:00 2001 From: Liam Date: Sun, 2 Jun 2024 01:04:42 -0400 Subject: [PATCH 18/35] Add OpenSearch XML description for browsers --- assets/static/opensearch.xml | 10 ++++++++++ lib/philomena_web.ex | 2 +- lib/philomena_web/templates/layout/app.html.slime | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 assets/static/opensearch.xml diff --git a/assets/static/opensearch.xml b/assets/static/opensearch.xml new file mode 100644 index 00000000..48909d2f --- /dev/null +++ b/assets/static/opensearch.xml @@ -0,0 +1,10 @@ + + Derpibooru + Derpibooru image search + UTF-8 + https://derpibooru.org/favicon.ico + https://derpibooru.org/favicon.svg + + + + diff --git a/lib/philomena_web.ex b/lib/philomena_web.ex index a4bccdf2..fd16f8ce 100644 --- a/lib/philomena_web.ex +++ b/lib/philomena_web.ex @@ -17,7 +17,7 @@ defmodule PhilomenaWeb do and import those modules here. """ - def static_paths, do: ~w(assets favicon.ico favicon.svg robots.txt) + def static_paths, do: ~w(assets favicon.ico favicon.svg robots.txt opensearch.xml) def controller do quote do diff --git a/lib/philomena_web/templates/layout/app.html.slime b/lib/philomena_web/templates/layout/app.html.slime index 29013972..d7842369 100644 --- a/lib/philomena_web/templates/layout/app.html.slime +++ b/lib/philomena_web/templates/layout/app.html.slime @@ -15,6 +15,7 @@ html lang="en" link rel="stylesheet" href=dark_stylesheet_path() media="(prefers-color-scheme: dark)" link rel="icon" href=~p"/favicon.ico" type="image/x-icon" link rel="icon" href=~p"/favicon.svg" type="image/svg+xml" + link rel="search" type="application/opensearchdescription+xml" title="Derpibooru" href=~p"/opensearch.xml" meta name="generator" content="philomena" meta name="theme-color" content="#618fc3" meta name="format-detection" content="telephone=no" From 9dd26f2f876afe9ea9a06543f82c195e2243550e Mon Sep 17 00:00:00 2001 From: KoloMl Date: Sun, 2 Jun 2024 19:58:01 +0400 Subject: [PATCH 19/35] Added separate property to control autocompletion mode This is better than using hardcoded field name. --- assets/js/autocomplete.js | 2 +- lib/philomena_web/templates/layout/_header.html.slime | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/js/autocomplete.js b/assets/js/autocomplete.js index 9ac4c2b8..28c0f409 100644 --- a/assets/js/autocomplete.js +++ b/assets/js/autocomplete.js @@ -27,7 +27,7 @@ function removeSelected() { } function isSearchField() { - return inputField && inputField.name === 'q'; + return inputField && inputField.dataset.acMode === 'search'; } function restoreOriginalValue() { diff --git a/lib/philomena_web/templates/layout/_header.html.slime b/lib/philomena_web/templates/layout/_header.html.slime index ea268bf3..406728ff 100644 --- a/lib/philomena_web/templates/layout/_header.html.slime +++ b/lib/philomena_web/templates/layout/_header.html.slime @@ -12,7 +12,7 @@ header.header i.fa.fa-upload = form_for @conn, Routes.search_path(@conn, :index), [method: "get", class: "header__search flex flex--no-wrap flex--centered", enforce_utf8: false], fn f -> - input.input.header__input.header__input--search#q name="q" title="For terms all required, separate with ',' or 'AND'; also supports 'OR' for optional terms and '-' or 'NOT' for negation. Search with a blank query for more options or click the ? for syntax help." value=@conn.params["q"] placeholder="Search" autocapitalize="none" autocomplete="off" data-ac="true" data-ac-min-length="3" data-ac-source="/autocomplete/tags?term=" + input.input.header__input.header__input--search#q name="q" title="For terms all required, separate with ',' or 'AND'; also supports 'OR' for optional terms and '-' or 'NOT' for negation. Search with a blank query for more options or click the ? for syntax help." value=@conn.params["q"] placeholder="Search" autocapitalize="none" autocomplete="off" data-ac="true" data-ac-min-length="3" data-ac-source="/autocomplete/tags?term=" data-ac-mode="search" = if present?(@conn.params["sf"]) do input type="hidden" name="sf" value=@conn.params["sf"] From 7fa141bb54f20531c940937cb0230893d739d6b8 Mon Sep 17 00:00:00 2001 From: KoloMl Date: Sun, 2 Jun 2024 19:59:06 +0400 Subject: [PATCH 20/35] Increased the suggestions count to 10 for search fields specifically Default 5 entries feel not enough for search field --- assets/js/autocomplete.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/assets/js/autocomplete.js b/assets/js/autocomplete.js index 28c0f409..b9ca92c5 100644 --- a/assets/js/autocomplete.js +++ b/assets/js/autocomplete.js @@ -200,10 +200,12 @@ function listenAutocomplete() { if (localAc !== null && 'ac' in event.target.dataset) { inputField = event.target; + let suggestionsCount = 5; if (isSearchField()) { originalQuery = inputField.value; selectedTerm = getSelectedTerm(); + suggestionsCount = 10; // We don't need to run auto-completion if user is not selecting tag at all if (!selectedTerm) { @@ -216,7 +218,7 @@ function listenAutocomplete() { originalTerm = `${inputField.value}`.toLowerCase(); } - const suggestions = localAc.topK(originalTerm, 5).map(({ name, imageCount }) => ({ label: `${name} (${imageCount})`, value: name })); + const suggestions = localAc.topK(originalTerm, suggestionsCount).map(({ name, imageCount }) => ({ label: `${name} (${imageCount})`, value: name })); if (suggestions.length) { return showAutocomplete(suggestions, originalTerm, event.target); From 1a7d59cb593c35908f59f6435a5a21a3654114ac Mon Sep 17 00:00:00 2001 From: KoloMl Date: Sun, 2 Jun 2024 20:40:09 +0400 Subject: [PATCH 21/35] Added the local setting to disable auto-completion --- assets/js/autocomplete.js | 12 ++++++++++++ lib/philomena_web/controllers/setting_controller.ex | 1 + lib/philomena_web/templates/setting/edit.html.slime | 4 ++++ 3 files changed, 17 insertions(+) diff --git a/assets/js/autocomplete.js b/assets/js/autocomplete.js index b9ca92c5..978c7cab 100644 --- a/assets/js/autocomplete.js +++ b/assets/js/autocomplete.js @@ -5,6 +5,7 @@ import { LocalAutocompleter } from './utils/local-autocompleter'; import { handleError } from './utils/requests'; import { getTermContexts } from './match_query'; +import store from './utils/store'; const cache = {}; /** @type {HTMLInputElement} */ @@ -184,6 +185,15 @@ function getSelectedTerm() { return terms.find(([range]) => range[0] < selectionIndex && range[1] >= selectionIndex); } +function toggleSearchAutocomplete() { + if (!store.get('disable_search_ac')) return; + + for (const searchField of document.querySelectorAll('input[data-ac-mode=search]')) { + searchField.removeAttribute('data-ac'); + searchField.autocomplete = 'on'; + } +} + function listenAutocomplete() { let timeout; @@ -268,6 +278,8 @@ function listenAutocomplete() { .then(buf => localAc = new LocalAutocompleter(buf)); } } + + toggleSearchAutocomplete(); } export { listenAutocomplete }; diff --git a/lib/philomena_web/controllers/setting_controller.ex b/lib/philomena_web/controllers/setting_controller.ex index 7c3d6db9..ce8aec3d 100644 --- a/lib/philomena_web/controllers/setting_controller.ex +++ b/lib/philomena_web/controllers/setting_controller.ex @@ -45,6 +45,7 @@ defmodule PhilomenaWeb.SettingController do |> set_cookie(user_params, "hide_uploader", "hide_uploader") |> set_cookie(user_params, "hide_score", "hide_score") |> set_cookie(user_params, "unfilter_tag_suggestions", "unfilter_tag_suggestions") + |> set_cookie(user_params, "disable_search_ac", "disable_search_ac") end defp set_cookie(conn, params, param_name, cookie_name) do diff --git a/lib/philomena_web/templates/setting/edit.html.slime b/lib/philomena_web/templates/setting/edit.html.slime index 92e13038..fd6677bb 100644 --- a/lib/philomena_web/templates/setting/edit.html.slime +++ b/lib/philomena_web/templates/setting/edit.html.slime @@ -174,6 +174,10 @@ h1 Content Settings => label f, :chan_nsfw, "Show NSFW channels" => checkbox f, :chan_nsfw, checked: @conn.cookies["chan_nsfw"] == "true" .fieldlabel: i Show streams marked as NSFW on the channels page. + .field + => label f, :disable_search_ac, "Disable search auto-completion" + => checkbox f, :disable_search_ac, checked: @conn.cookies["disable_search_ac"] === "true" + .fieldlabel: i Disable the auto-completion of tags in the search fields. This will bring back default browser's behaviour. = if staff?(@conn.assigns.current_user) do .field => label f, :hide_staff_tools From ed34dea36f84ab70e9e7217949b193c52a1ac0e9 Mon Sep 17 00:00:00 2001 From: Liam Date: Sun, 2 Jun 2024 00:49:01 -0400 Subject: [PATCH 22/35] Swap Bamboo for Swoosh email delivery --- config/config.exs | 1 - config/runtime.exs | 22 +++++++++------------- lib/philomena/application.ex | 3 +++ lib/philomena/mailer.ex | 8 +++++++- lib/philomena/users/user_notifier.ex | 4 ++-- mix.exs | 9 +++------ mix.lock | 6 +++--- 7 files changed, 27 insertions(+), 26 deletions(-) diff --git a/config/config.exs b/config/config.exs index 2c797a1a..9d943587 100644 --- a/config/config.exs +++ b/config/config.exs @@ -58,7 +58,6 @@ config :logger, :console, # Use Jason for JSON parsing in Phoenix config :phoenix, :json_library, Jason -config :bamboo, :json_library, Jason # Import environment specific config. This must remain at the bottom # of this file so it overrides the configuration defined above. diff --git a/config/runtime.exs b/config/runtime.exs index 4257ed9e..935ba124 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -6,7 +6,6 @@ import Config # by calling `mix release`. # # See `mix help release` for more information. -{:ok, _} = Application.ensure_all_started(:tls_certificate_check) config :bcrypt_elixir, log_rounds: String.to_integer(System.get_env("BCRYPT_ROUNDS", "12")) @@ -118,17 +117,14 @@ end if config_env() == :prod do # Production mailer config config :philomena, Philomena.Mailer, - adapter: Bamboo.SMTPAdapter, - server: System.fetch_env!("SMTP_RELAY"), - hostname: System.fetch_env!("SMTP_DOMAIN"), - port: System.get_env("SMTP_PORT") || 587, - username: System.fetch_env!("SMTP_USERNAME"), - password: System.fetch_env!("SMTP_PASSWORD"), - tls: :always, - auth: :always, - tls_options: - [middlebox_comp_mode: false] ++ - :tls_certificate_check.options(System.fetch_env!("SMTP_RELAY")) + adapter: Swoosh.Adapters.Mua, + relay: System.fetch_env!("SMTP_RELAY"), + port: String.to_integer(System.get_env("SMTP_PORT", "587")), + auth: [ + username: System.fetch_env!("SMTP_USERNAME"), + password: System.fetch_env!("SMTP_PASSWORD") + ], + ssl: [middlebox_comp_mode: false] # Production endpoint config {:ok, ip} = :inet.parse_address(System.get_env("APP_IP", "127.0.0.1") |> String.to_charlist()) @@ -140,7 +136,7 @@ if config_env() == :prod do server: not is_nil(System.get_env("START_ENDPOINT")) else # Don't send email in development - config :philomena, Philomena.Mailer, adapter: Bamboo.LocalAdapter + config :philomena, Philomena.Mailer, adapter: Swoosh.Adapters.Local # Use this to debug slime templates # config :slime, :keep_lines, true diff --git a/lib/philomena/application.ex b/lib/philomena/application.ex index 28d7d645..4d1a7a4b 100644 --- a/lib/philomena/application.ex +++ b/lib/philomena/application.ex @@ -14,6 +14,9 @@ defmodule Philomena.Application do # Background queueing system Philomena.ExqSupervisor, + # Mailer + {Task.Supervisor, name: Philomena.AsyncEmailSupervisor}, + # Starts a worker by calling: Philomena.Worker.start_link(arg) # {Philomena.Worker, arg}, {Redix, name: :redix, host: Application.get_env(:philomena, :redis_host)}, diff --git a/lib/philomena/mailer.ex b/lib/philomena/mailer.ex index 93bed3ba..642f329e 100644 --- a/lib/philomena/mailer.ex +++ b/lib/philomena/mailer.ex @@ -1,3 +1,9 @@ defmodule Philomena.Mailer do - use Bamboo.Mailer, otp_app: :philomena + use Swoosh.Mailer, otp_app: :philomena + + @spec deliver_later(Swoosh.Email.t()) :: {:ok, Swoosh.Email.t()} + def deliver_later(mail) do + Task.Supervisor.start_child(Philomena.AsyncEmailSupervisor, fn -> deliver(mail) end) + {:ok, mail} + end end diff --git a/lib/philomena/users/user_notifier.ex b/lib/philomena/users/user_notifier.ex index bc8b71db..48083321 100644 --- a/lib/philomena/users/user_notifier.ex +++ b/lib/philomena/users/user_notifier.ex @@ -1,9 +1,9 @@ defmodule Philomena.Users.UserNotifier do - alias Bamboo.Email + alias Swoosh.Email alias Philomena.Mailer defp deliver(to, subject, body) do - Email.new_email( + Email.new( to: to, from: mailer_address(), subject: subject, diff --git a/mix.exs b/mix.exs index 85d5c270..130f1ccc 100644 --- a/mix.exs +++ b/mix.exs @@ -62,7 +62,6 @@ defmodule Philomena.MixProject do github: "basho/erlang-pbkdf2", ref: "7e9bd5fcd3cc3062159e4c9214bb628aa6feb5ca"}, {:qrcode, "~> 0.1"}, {:redix, "~> 1.2"}, - {:bamboo, "~> 2.2"}, {:remote_ip, "~> 1.1"}, {:briefly, "~> 0.4"}, {:tesla, "~> 1.5"}, @@ -76,11 +75,9 @@ defmodule Philomena.MixProject do {:inet_cidr, "~> 1.0"}, # SMTP - {:tls_certificate_check, "~> 1.21"}, - {:bamboo_smtp, "~> 4.2", - github: "botsquad/bamboo_smtp", - ref: "c630ccde40070deffc7d78ee6e4a08c9199f145b", - override: true}, + {:swoosh, "~> 1.16"}, + {:mua, "~> 0.2.0"}, + {:mail, "~> 0.3.0"}, # Markdown {:rustler, "~> 0.27"}, diff --git a/mix.lock b/mix.lock index 522e7676..73184f5a 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,4 @@ %{ - "bamboo": {:hex, :bamboo, "2.2.0", "f10a406d2b7f5123eb1f02edfa043c259db04b47ab956041f279eaac776ef5ce", [:mix], [{:hackney, ">= 1.15.2", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.4", [hex: :mime, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "8c3b14ba7d2f40cb4be04128ed1e2aff06d91d9413d38bafb4afccffa3ade4fc"}, - "bamboo_smtp": {:git, "https://github.com/botsquad/bamboo_smtp.git", "c630ccde40070deffc7d78ee6e4a08c9199f145b", [ref: "c630ccde40070deffc7d78ee6e4a08c9199f145b"]}, "bcrypt_elixir": {:hex, :bcrypt_elixir, "3.1.0", "0b110a9a6c619b19a7f73fa3004aa11d6e719a67e672d1633dc36b6b2290a0f7", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "2ad2acb5a8bc049e8d5aa267802631912bb80d5f4110a178ae7999e69dca1bf7"}, "briefly": {:hex, :briefly, "0.5.1", "ee10d48da7f79ed2aebdc3e536d5f9a0c3e36ff76c0ad0d4254653a152b13a8a", [:mix], [], "hexpm", "bd684aa92ad8b7b4e0d92c31200993c4bc1469fc68cd6d5f15144041bd15cb57"}, "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, @@ -40,11 +38,13 @@ "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, "inet_cidr": {:hex, :inet_cidr, "1.0.8", "d26bb7bdbdf21ae401ead2092bf2bb4bf57fe44a62f5eaa5025280720ace8a40", [:mix], [], "hexpm", "d5b26da66603bb56c933c65214c72152f0de9a6ea53618b56d63302a68f6a90e"}, "jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"}, + "mail": {:hex, :mail, "0.3.1", "cb0a14e4ed8904e4e5a08214e686ccf6f9099346885db17d8c309381f865cc5c", [:mix], [], "hexpm", "1db701e89865c1d5fa296b2b57b1cd587587cca8d8a1a22892b35ef5a8e352a6"}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, "mime": {:hex, :mime, "1.6.0", "dabde576a497cef4bbdd60aceee8160e02a6c89250d6c0b29e56c0dfb00db3d2", [:mix], [], "hexpm", "31a1a8613f8321143dde1dafc36006a17d28d02bdfecb9e95a880fa7aabd19a7"}, "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"}, "mint": {:hex, :mint, "1.5.2", "4805e059f96028948870d23d7783613b7e6b0e2fb4e98d720383852a760067fd", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "d77d9e9ce4eb35941907f1d3df38d8f750c357865353e21d335bdcdf6d892a02"}, "mix_audit": {:hex, :mix_audit, "2.1.2", "6cd5c5e2edbc9298629c85347b39fb3210656e541153826efd0b2a63767f3395", [:make, :mix], [{:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.9", [hex: :yaml_elixir, repo: "hexpm", optional: false]}], "hexpm", "68d2f06f96b9c445a23434c9d5f09682866a5b4e90f631829db1c64f140e795b"}, + "mua": {:hex, :mua, "0.2.1", "7f1c20dbe7266d514a07bf5b7a3946413d70150be41cb5475b5a95bb517a378f", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "0bc556803a1d09dfb69bfebecb838cf33a2d123de84f700c41b6b8134027c11f"}, "neotoma": {:hex, :neotoma, "1.7.3", "d8bd5404b73273989946e4f4f6d529e5c2088f5fa1ca790b4dbe81f4be408e61", [:rebar], [], "hexpm", "2da322b9b1567ffa0706a7f30f6bbbde70835ae44a1050615f4b4a3d436e0f28"}, "nimble_options": {:hex, :nimble_options, "1.1.0", "3b31a57ede9cb1502071fade751ab0c7b8dbe75a9a4c2b5bbb0943a690b63172", [:mix], [], "hexpm", "8bbbb3941af3ca9acc7835f5655ea062111c9c27bcac53e004460dfd19008a99"}, "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, @@ -78,9 +78,9 @@ "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"}, "sweet_xml": {:hex, :sweet_xml, "0.7.4", "a8b7e1ce7ecd775c7e8a65d501bc2cd933bff3a9c41ab763f5105688ef485d08", [:mix], [], "hexpm", "e7c4b0bdbf460c928234951def54fe87edf1a170f6896675443279e2dbeba167"}, + "swoosh": {:hex, :swoosh, "1.16.9", "20c6a32ea49136a4c19f538e27739bb5070558c0fa76b8a95f4d5d5ca7d319a1", [:mix], [{:bandit, ">= 1.0.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mua, "~> 0.2.0", [hex: :mua, repo: "hexpm", optional: true]}, {:multipart, "~> 0.4", [hex: :multipart, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:req, "~> 0.5 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "878b1a7a6c10ebbf725a3349363f48f79c5e3d792eb621643b0d276a38acc0a6"}, "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"}, "tesla": {:hex, :tesla, "1.8.0", "d511a4f5c5e42538d97eef7c40ec4f3e44effdc5068206f42ed859e09e51d1fd", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.13", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, ">= 1.0.0", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.2", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:msgpax, "~> 2.3", [hex: :msgpax, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "10501f360cd926a309501287470372af1a6e1cbed0f43949203a4c13300bc79f"}, - "tls_certificate_check": {:hex, :tls_certificate_check, "1.21.0", "042ab2c0c860652bc5cf69c94e3a31f96676d14682e22ec7813bd173ceff1788", [:rebar3], [{:ssl_verify_fun, "~> 1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "6cee6cffc35a390840d48d463541d50746a7b0e421acaadb833cfc7961e490e7"}, "toml": {:hex, :toml, "0.7.0", "fbcd773caa937d0c7a02c301a1feea25612720ac3fa1ccb8bfd9d30d822911de", [:mix], [], "hexpm", "0690246a2478c1defd100b0c9b89b4ea280a22be9a7b313a8a058a2408a2fa70"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, "websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"}, From c63bc41d8b15947e1b1d86d650f99b30eb97aaeb Mon Sep 17 00:00:00 2001 From: Liam Date: Fri, 24 May 2024 21:15:05 -0400 Subject: [PATCH 23/35] Split out HTTP client interaction into PhilomenaProxy namespace --- lib/camo/image.ex | 8 -- .../artist_links/automatic_verifier.ex | 2 +- lib/philomena/channels/picarto_channel.ex | 2 +- lib/philomena/channels/piczel_channel.ex | 2 +- lib/philomena/http.ex | 46 -------- lib/philomena/scrapers.ex | 25 ---- lib/philomena_proxy/camo.ex | 24 ++++ lib/philomena_proxy/http.ex | 107 ++++++++++++++++++ lib/philomena_proxy/scrapers.ex | 71 ++++++++++++ .../scrapers/deviantart.ex | 21 +++- .../scrapers/pillowfort.ex | 14 ++- .../scrapers/raw.ex | 18 ++- lib/philomena_proxy/scrapers/scraper.ex | 11 ++ .../scrapers/tumblr.ex | 18 ++- .../scrapers/twitter.ex | 16 ++- .../controllers/image/scrape_controller.ex | 2 +- lib/philomena_web/plugs/check_captcha_plug.ex | 2 +- .../plugs/compromised_password_check_plug.ex | 2 +- lib/philomena_web/plugs/scraper_plug.ex | 2 +- lib/philomena_web/views/channel_view.ex | 12 +- priv/repo/seeds_development.exs | 2 +- 21 files changed, 294 insertions(+), 113 deletions(-) delete mode 100644 lib/camo/image.ex delete mode 100644 lib/philomena/http.ex delete mode 100644 lib/philomena/scrapers.ex create mode 100644 lib/philomena_proxy/camo.ex create mode 100644 lib/philomena_proxy/http.ex create mode 100644 lib/philomena_proxy/scrapers.ex rename lib/{philomena => philomena_proxy}/scrapers/deviantart.ex (89%) rename lib/{philomena => philomena_proxy}/scrapers/pillowfort.ex (78%) rename lib/{philomena => philomena_proxy}/scrapers/raw.ex (56%) create mode 100644 lib/philomena_proxy/scrapers/scraper.ex rename lib/{philomena => philomena_proxy}/scrapers/tumblr.ex (84%) rename lib/{philomena => philomena_proxy}/scrapers/twitter.ex (61%) diff --git a/lib/camo/image.ex b/lib/camo/image.ex deleted file mode 100644 index e77f99e6..00000000 --- a/lib/camo/image.ex +++ /dev/null @@ -1,8 +0,0 @@ -defmodule Camo.Image do - @doc """ - Convert a potentially untrusted external image URL into a trusted one - loaded through a gocamo proxy (specified by the environment). - """ - @spec image_url(String.t()) :: String.t() - def image_url(input), do: Philomena.Native.camo_image_url(input) -end diff --git a/lib/philomena/artist_links/automatic_verifier.ex b/lib/philomena/artist_links/automatic_verifier.ex index 1fd303a4..57fd8fd2 100644 --- a/lib/philomena/artist_links/automatic_verifier.ex +++ b/lib/philomena/artist_links/automatic_verifier.ex @@ -1,7 +1,7 @@ defmodule Philomena.ArtistLinks.AutomaticVerifier do def check_link(artist_link, recheck_time) do artist_link.uri - |> Philomena.Http.get() + |> PhilomenaProxy.Http.get() |> contains_verification_code?(artist_link.verification_code) |> case do true -> diff --git a/lib/philomena/channels/picarto_channel.ex b/lib/philomena/channels/picarto_channel.ex index cc54cdd6..a27a3615 100644 --- a/lib/philomena/channels/picarto_channel.ex +++ b/lib/philomena/channels/picarto_channel.ex @@ -4,7 +4,7 @@ defmodule Philomena.Channels.PicartoChannel do @spec live_channels(DateTime.t()) :: map() def live_channels(now) do @api_online - |> Philomena.Http.get() + |> PhilomenaProxy.Http.get() |> case do {:ok, %Tesla.Env{body: body, status: 200}} -> body diff --git a/lib/philomena/channels/piczel_channel.ex b/lib/philomena/channels/piczel_channel.ex index 23ce8a0d..56da9e34 100644 --- a/lib/philomena/channels/piczel_channel.ex +++ b/lib/philomena/channels/piczel_channel.ex @@ -4,7 +4,7 @@ defmodule Philomena.Channels.PiczelChannel do @spec live_channels(DateTime.t()) :: map() def live_channels(now) do @api_online - |> Philomena.Http.get() + |> PhilomenaProxy.Http.get() |> case do {:ok, %Tesla.Env{body: body, status: 200}} -> body diff --git a/lib/philomena/http.ex b/lib/philomena/http.ex deleted file mode 100644 index 738d8a11..00000000 --- a/lib/philomena/http.ex +++ /dev/null @@ -1,46 +0,0 @@ -defmodule Philomena.Http do - def get(url, headers \\ [], options \\ []) do - Tesla.get(client(headers), url, opts: [adapter: adapter_opts(options)]) - end - - def head(url, headers \\ [], options \\ []) do - Tesla.head(client(headers), url, opts: [adapter: adapter_opts(options)]) - end - - def post(url, body, headers \\ [], options \\ []) do - Tesla.post(client(headers), url, body, opts: [adapter: adapter_opts(options)]) - end - - defp adapter_opts(opts) do - opts = Keyword.merge(opts, max_body: 125_000_000, inet6: true) - - case Application.get_env(:philomena, :proxy_host) do - nil -> - opts - - url -> - Keyword.merge(opts, proxy: proxy_opts(URI.parse(url))) - end - end - - defp proxy_opts(%{host: host, port: port, scheme: "https"}), - do: {:https, host, port, [transport_opts: [inet6: true]]} - - defp proxy_opts(%{host: host, port: port, scheme: "http"}), - do: {:http, host, port, [transport_opts: [inet6: true]]} - - defp client(headers) do - Tesla.client( - [ - {Tesla.Middleware.FollowRedirects, max_redirects: 1}, - {Tesla.Middleware.Headers, - [ - {"User-Agent", - "Mozilla/5.0 (X11; Philomena; Linux x86_64; rv:86.0) Gecko/20100101 Firefox/86.0"} - | headers - ]} - ], - Tesla.Adapter.Mint - ) - end -end diff --git a/lib/philomena/scrapers.ex b/lib/philomena/scrapers.ex deleted file mode 100644 index da5fd381..00000000 --- a/lib/philomena/scrapers.ex +++ /dev/null @@ -1,25 +0,0 @@ -defmodule Philomena.Scrapers do - @scrapers [ - Philomena.Scrapers.Deviantart, - Philomena.Scrapers.Pillowfort, - Philomena.Scrapers.Twitter, - Philomena.Scrapers.Tumblr, - Philomena.Scrapers.Raw - ] - - def scrape!(url) do - uri = URI.parse(url) - - @scrapers - |> Enum.find(& &1.can_handle?(uri, url)) - |> wrap() - |> Enum.map(& &1.scrape(uri, url)) - |> unwrap() - end - - defp wrap(nil), do: [] - defp wrap(res), do: [res] - - defp unwrap([result]), do: result - defp unwrap(_result), do: nil -end diff --git a/lib/philomena_proxy/camo.ex b/lib/philomena_proxy/camo.ex new file mode 100644 index 00000000..881b1c39 --- /dev/null +++ b/lib/philomena_proxy/camo.ex @@ -0,0 +1,24 @@ +defmodule PhilomenaProxy.Camo do + @moduledoc """ + Image proxying utilities. + """ + + @doc """ + Convert a potentially untrusted external image URL into a trusted one + loaded through a gocamo proxy (specified by the environment). + + Configuration is read from environment variables at runtime by Philomena. + + config :philomena, + camo_host: System.get_env("CAMO_HOST"), + camo_key: System.get_env("CAMO_KEY"), + + ## Example + + iex> PhilomenaProxy.Camo.image_url("https://example.org/img/view/2024/1/1/1.png") + "https://example.net/L5MqSmYq1ZEqiBGGvsvSDpILyJI/aHR0cHM6Ly9leGFtcGxlLm9yZy9pbWcvdmlldy8yMDI0LzEvMS8xLnBuZwo" + + """ + @spec image_url(String.t()) :: String.t() + def image_url(input), do: Philomena.Native.camo_image_url(input) +end diff --git a/lib/philomena_proxy/http.ex b/lib/philomena_proxy/http.ex new file mode 100644 index 00000000..9a5af4ec --- /dev/null +++ b/lib/philomena_proxy/http.ex @@ -0,0 +1,107 @@ +defmodule PhilomenaProxy.Http do + @moduledoc """ + HTTP client implementation. + + This applies the Philomena User-Agent header, and optionally proxies traffic through a SOCKS5 + HTTP proxy to allow the application to connect when the local network is restricted. + + If a proxy host is not specified in the configuration, then a proxy is not used and external + traffic is originated from the same network as application. + + Proxy options are read from environment variables at runtime by Philomena. + + config :philomena, + proxy_host: System.get_env("PROXY_HOST"), + + """ + + @type url :: String.t() + @type header_list :: [{String.t(), String.t()}] + @type body :: binary() + + @type client_options :: keyword() + + @doc ~S""" + Perform a HTTP GET request. + + ## Example + + iex> PhilomenaProxy.Http.get("http://example.com", [{"authorization", "Bearer #{token}"}]) + {:ok, %Tesla.Env{...}} + + iex> PhilomenaProxy.Http.get("http://nonexistent.example.com") + {:error, %Mint.TransportError{reason: :nxdomain}} + + """ + @spec get(url(), header_list(), client_options()) :: Tesla.Env.result() + def get(url, headers \\ [], options \\ []) do + Tesla.get(client(headers), url, opts: [adapter: adapter_opts(options)]) + end + + @doc ~S""" + Perform a HTTP HEAD request. + + ## Example + + iex> PhilomenaProxy.Http.head("http://example.com", [{"authorization", "Bearer #{token}"}]) + {:ok, %Tesla.Env{...}} + + iex> PhilomenaProxy.Http.head("http://nonexistent.example.com") + {:error, %Mint.TransportError{reason: :nxdomain}} + + """ + @spec head(url(), header_list(), client_options()) :: Tesla.Env.result() + def head(url, headers \\ [], options \\ []) do + Tesla.head(client(headers), url, opts: [adapter: adapter_opts(options)]) + end + + @doc ~S""" + Perform a HTTP POST request. + + ## Example + + iex> PhilomenaProxy.Http.post("http://example.com", "", [{"authorization", "Bearer #{token}"}]) + {:ok, %Tesla.Env{...}} + + iex> PhilomenaProxy.Http.post("http://nonexistent.example.com", "") + {:error, %Mint.TransportError{reason: :nxdomain}} + + """ + @spec post(url(), body(), header_list(), client_options()) :: Tesla.Env.result() + def post(url, body, headers \\ [], options \\ []) do + Tesla.post(client(headers), url, body, opts: [adapter: adapter_opts(options)]) + end + + defp adapter_opts(opts) do + opts = Keyword.merge(opts, max_body: 125_000_000, inet6: true) + + case Application.get_env(:philomena, :proxy_host) do + nil -> + opts + + url -> + Keyword.merge(opts, proxy: proxy_opts(URI.parse(url))) + end + end + + defp proxy_opts(%{host: host, port: port, scheme: "https"}), + do: {:https, host, port, [transport_opts: [inet6: true]]} + + defp proxy_opts(%{host: host, port: port, scheme: "http"}), + do: {:http, host, port, [transport_opts: [inet6: true]]} + + defp client(headers) do + Tesla.client( + [ + {Tesla.Middleware.FollowRedirects, max_redirects: 1}, + {Tesla.Middleware.Headers, + [ + {"User-Agent", + "Mozilla/5.0 (X11; Philomena; Linux x86_64; rv:86.0) Gecko/20100101 Firefox/86.0"} + | headers + ]} + ], + Tesla.Adapter.Mint + ) + end +end diff --git a/lib/philomena_proxy/scrapers.ex b/lib/philomena_proxy/scrapers.ex new file mode 100644 index 00000000..9a166887 --- /dev/null +++ b/lib/philomena_proxy/scrapers.ex @@ -0,0 +1,71 @@ +defmodule PhilomenaProxy.Scrapers do + @moduledoc """ + Scrape utilities to facilitate uploading media from other websites. + """ + + # The URL to fetch, as a string. + @type url :: String.t() + + # An individual image in a list associated with a scrape result. + @type image_result :: %{ + url: url(), + camo_url: url() + } + + # Result of a successful scrape. + @type scrape_result :: %{ + source_url: url(), + description: String.t() | nil, + author_name: String.t() | nil, + images: [image_result()] + } + + @scrapers [ + PhilomenaProxy.Scrapers.Deviantart, + PhilomenaProxy.Scrapers.Pillowfort, + PhilomenaProxy.Scrapers.Twitter, + PhilomenaProxy.Scrapers.Tumblr, + PhilomenaProxy.Scrapers.Raw + ] + + @doc """ + Scrape a URL for content. + + The scrape result is intended for serialization to JSON. + + ## Examples + + iex> PhilomenaProxy.Scrapers.scrape!("http://example.org/image-page") + %{ + source_url: "http://example.org/image-page", + description: "Test", + author_name: "myself", + images: [ + %{ + url: "http://example.org/image.png" + camo_url: "http://example.net/UT2YIjkWDas6CQBmQcYlcNGmKfQ/aHR0cDovL2V4YW1wbGUub3JnL2ltY" + } + ] + } + + iex> PhilomenaProxy.Scrapers.scrape!("http://example.org/nonexistent-path") + nil + + """ + @spec scrape!(url()) :: scrape_result() | nil + def scrape!(url) do + uri = URI.parse(url) + + @scrapers + |> Enum.find(& &1.can_handle?(uri, url)) + |> wrap() + |> Enum.map(& &1.scrape(uri, url)) + |> unwrap() + end + + defp wrap(nil), do: [] + defp wrap(res), do: [res] + + defp unwrap([result]), do: result + defp unwrap(_result), do: nil +end diff --git a/lib/philomena/scrapers/deviantart.ex b/lib/philomena_proxy/scrapers/deviantart.ex similarity index 89% rename from lib/philomena/scrapers/deviantart.ex rename to lib/philomena_proxy/scrapers/deviantart.ex index 4bc8fdd9..10985133 100644 --- a/lib/philomena/scrapers/deviantart.ex +++ b/lib/philomena_proxy/scrapers/deviantart.ex @@ -1,4 +1,11 @@ -defmodule Philomena.Scrapers.Deviantart do +defmodule PhilomenaProxy.Scrapers.Deviantart do + @moduledoc false + + alias PhilomenaProxy.Scrapers.Scraper + alias PhilomenaProxy.Scrapers + + @behaviour Scraper + @image_regex ~r|data-rh="true" rel="preload" href="([^"]*)" as="image"| @source_regex ~r|rel="canonical" href="([^"]*)"| @artist_regex ~r|https://www.deviantart.com/([^/]*)/art| @@ -7,7 +14,7 @@ defmodule Philomena.Scrapers.Deviantart do @png_regex ~r|(https://[0-9a-z\-\.]+(?:/intermediary)?/f/[0-9a-f\-]+/[0-9a-z\-]+\.png/v1/fill/[0-9a-z_,]+/[0-9a-z_\-]+)(\.png)(.*)| @jpg_regex ~r|(https://[0-9a-z\-\.]+(?:/intermediary)?/f/[0-9a-f\-]+/[0-9a-z\-]+\.jpg/v1/fill/w_[0-9]+,h_[0-9]+,q_)([0-9]+)(,[a-z]+\/[a-z0-6_\-]+\.jpe?g.*)| - @spec can_handle?(URI.t(), String.t()) :: true | false + @spec can_handle?(URI.t(), String.t()) :: boolean() def can_handle?(uri, _url) do String.ends_with?(uri.host, "deviantart.com") end @@ -21,6 +28,7 @@ defmodule Philomena.Scrapers.Deviantart do # # So, regex it is. Eat dirt, deviantart. You don't deserve the respect # artists give you. + @spec scrape(URI.t(), Scrapers.url()) :: Scrapers.scrape_result() def scrape(_uri, url) do url |> follow_redirect(2) @@ -38,10 +46,11 @@ defmodule Philomena.Scrapers.Deviantart do %{ source_url: source, author_name: artist, + description: "", images: [ %{ url: image, - camo_url: Camo.Image.image_url(image) + camo_url: PhilomenaProxy.Camo.image_url(image) } ] } @@ -51,7 +60,7 @@ defmodule Philomena.Scrapers.Deviantart do with [domain, object_uuid, object_name] <- Regex.run(@cdnint_regex, image.url, capture: :all_but_first), built_url <- "#{domain}/intermediary/f/#{object_uuid}/#{object_name}", - {:ok, %Tesla.Env{status: 200}} <- Philomena.Http.head(built_url) do + {:ok, %Tesla.Env{status: 200}} <- PhilomenaProxy.Http.head(built_url) do # This is the high resolution URL. %{ data @@ -110,7 +119,7 @@ defmodule Philomena.Scrapers.Deviantart do built_url = "http://orig01.deviantart.net/x_by_x-d#{base36}.png" - case Philomena.Http.get(built_url) do + case PhilomenaProxy.Http.get(built_url) do {:ok, %Tesla.Env{status: 301, headers: headers}} -> # Location header provides URL of high res image. {_location, link} = Enum.find(headers, fn {header, _val} -> header == "location" end) @@ -135,7 +144,7 @@ defmodule Philomena.Scrapers.Deviantart do defp follow_redirect(_url, 0), do: nil defp follow_redirect(url, max_times) do - case Philomena.Http.get(url) do + case PhilomenaProxy.Http.get(url) do {:ok, %Tesla.Env{headers: headers, status: code}} when code in [301, 302] -> location = Enum.find_value(headers, &location_header/1) follow_redirect(location, max_times - 1) diff --git a/lib/philomena/scrapers/pillowfort.ex b/lib/philomena_proxy/scrapers/pillowfort.ex similarity index 78% rename from lib/philomena/scrapers/pillowfort.ex rename to lib/philomena_proxy/scrapers/pillowfort.ex index b577c819..6e083c9c 100755 --- a/lib/philomena/scrapers/pillowfort.ex +++ b/lib/philomena_proxy/scrapers/pillowfort.ex @@ -1,4 +1,11 @@ -defmodule Philomena.Scrapers.Pillowfort do +defmodule PhilomenaProxy.Scrapers.Pillowfort do + @moduledoc false + + alias PhilomenaProxy.Scrapers.Scraper + alias PhilomenaProxy.Scrapers + + @behaviour Scraper + @url_regex ~r|\Ahttps?://www\.pillowfort\.social/posts/([0-9]+)| @spec can_handle?(URI.t(), String.t()) :: boolean() @@ -6,12 +13,13 @@ defmodule Philomena.Scrapers.Pillowfort do String.match?(url, @url_regex) end + @spec scrape(URI.t(), Scrapers.url()) :: Scrapers.scrape_result() def scrape(_uri, url) do [post_id] = Regex.run(@url_regex, url, capture: :all_but_first) api_url = "https://www.pillowfort.social/posts/#{post_id}/json" - Philomena.Http.get(api_url) + PhilomenaProxy.Http.get(api_url) |> json!() |> process_response!(url) end @@ -25,7 +33,7 @@ defmodule Philomena.Scrapers.Pillowfort do |> Enum.map( &%{ url: &1["url"], - camo_url: Camo.Image.image_url(&1["small_image_url"]) + camo_url: PhilomenaProxy.Camo.image_url(&1["small_image_url"]) } ) diff --git a/lib/philomena/scrapers/raw.ex b/lib/philomena_proxy/scrapers/raw.ex similarity index 56% rename from lib/philomena/scrapers/raw.ex rename to lib/philomena_proxy/scrapers/raw.ex index 0085f54c..ed31d10b 100644 --- a/lib/philomena/scrapers/raw.ex +++ b/lib/philomena_proxy/scrapers/raw.ex @@ -1,9 +1,16 @@ -defmodule Philomena.Scrapers.Raw do +defmodule PhilomenaProxy.Scrapers.Raw do + @moduledoc false + + alias PhilomenaProxy.Scrapers.Scraper + alias PhilomenaProxy.Scrapers + + @behaviour Scraper + @mime_types ["image/gif", "image/jpeg", "image/png", "image/svg", "image/svg+xml", "video/webm"] - @spec can_handle?(URI.t(), String.t()) :: true | false + @spec can_handle?(URI.t(), String.t()) :: boolean() def can_handle?(_uri, url) do - Philomena.Http.head(url) + PhilomenaProxy.Http.head(url) |> case do {:ok, %Tesla.Env{status: 200, headers: headers}} -> headers @@ -16,13 +23,16 @@ defmodule Philomena.Scrapers.Raw do end end + @spec scrape(URI.t(), Scrapers.url()) :: Scrapers.scrape_result() def scrape(_uri, url) do %{ source_url: url, + author_name: "", + description: "", images: [ %{ url: url, - camo_url: Camo.Image.image_url(url) + camo_url: PhilomenaProxy.Camo.image_url(url) } ] } diff --git a/lib/philomena_proxy/scrapers/scraper.ex b/lib/philomena_proxy/scrapers/scraper.ex new file mode 100644 index 00000000..15cedcea --- /dev/null +++ b/lib/philomena_proxy/scrapers/scraper.ex @@ -0,0 +1,11 @@ +defmodule PhilomenaProxy.Scrapers.Scraper do + @moduledoc false + + alias PhilomenaProxy.Scrapers + + # Return whether the given URL can be parsed by the scraper + @callback can_handle?(URI.t(), Scrapers.url()) :: boolean() + + # Collect upload information from the URL + @callback scrape(URI.t(), Scrapers.url()) :: Scrapers.scrape_result() +end diff --git a/lib/philomena/scrapers/tumblr.ex b/lib/philomena_proxy/scrapers/tumblr.ex similarity index 84% rename from lib/philomena/scrapers/tumblr.ex rename to lib/philomena_proxy/scrapers/tumblr.ex index 61ec1def..fe648e66 100644 --- a/lib/philomena/scrapers/tumblr.ex +++ b/lib/philomena_proxy/scrapers/tumblr.ex @@ -1,4 +1,11 @@ -defmodule Philomena.Scrapers.Tumblr do +defmodule PhilomenaProxy.Scrapers.Tumblr do + @moduledoc false + + alias PhilomenaProxy.Scrapers.Scraper + alias PhilomenaProxy.Scrapers + + @behaviour Scraper + @url_regex ~r|\Ahttps?://(?:.*)/(?:image\|post)/(\d+)(?:\z\|[/?#])| @media_regex ~r|https?://(?:\d+\.)?media\.tumblr\.com/[a-f\d]+/[a-f\d]+-[a-f\d]+/s\d+x\d+/[a-f\d]+\.(?:png\|jpe?g\|gif)|i @size_regex ~r|_(\d+)(\..+)\z| @@ -18,13 +25,14 @@ defmodule Philomena.Scrapers.Tumblr do String.match?(url, @url_regex) and tumblr_domain?(uri.host) end + @spec scrape(URI.t(), Scrapers.url()) :: Scrapers.scrape_result() def scrape(uri, url) do [post_id] = Regex.run(@url_regex, url, capture: :all_but_first) api_url = "https://api.tumblr.com/v2/blog/#{uri.host}/posts/photo?id=#{post_id}&api_key=#{tumblr_api_key()}" - Philomena.Http.get(api_url) + PhilomenaProxy.Http.get(api_url) |> json!() |> process_response!() end @@ -44,7 +52,7 @@ defmodule Philomena.Scrapers.Tumblr do %{"url" => preview} = Enum.find(photo["alt_sizes"], &(&1["width"] == 400)) || %{"url" => image} - %{url: image, camo_url: Camo.Image.image_url(preview)} + %{url: image, camo_url: PhilomenaProxy.Camo.image_url(preview)} end) add_meta(post, images) @@ -55,7 +63,7 @@ defmodule Philomena.Scrapers.Tumblr do @media_regex |> Regex.scan(post["body"]) |> Enum.map(fn [url | _captures] -> - %{url: url, camo_url: Camo.Image.image_url(url)} + %{url: url, camo_url: PhilomenaProxy.Camo.image_url(url)} end) add_meta(post, images) @@ -68,7 +76,7 @@ defmodule Philomena.Scrapers.Tumblr do end defp url_ok?(url) do - match?({:ok, %Tesla.Env{status: 200}}, Philomena.Http.head(url)) + match?({:ok, %Tesla.Env{status: 200}}, PhilomenaProxy.Http.head(url)) end defp add_meta(post, images) do diff --git a/lib/philomena/scrapers/twitter.ex b/lib/philomena_proxy/scrapers/twitter.ex similarity index 61% rename from lib/philomena/scrapers/twitter.ex rename to lib/philomena_proxy/scrapers/twitter.ex index 0ba64180..def1a374 100644 --- a/lib/philomena/scrapers/twitter.ex +++ b/lib/philomena_proxy/scrapers/twitter.ex @@ -1,16 +1,24 @@ -defmodule Philomena.Scrapers.Twitter do +defmodule PhilomenaProxy.Scrapers.Twitter do + @moduledoc false + + alias PhilomenaProxy.Scrapers.Scraper + alias PhilomenaProxy.Scrapers + + @behaviour Scraper + @url_regex ~r|\Ahttps?://(?:mobile\.)?(?:twitter\|x).com/([A-Za-z\d_]+)/status/([\d]+)/?| - @spec can_handle?(URI.t(), String.t()) :: true | false + @spec can_handle?(URI.t(), String.t()) :: boolean() def can_handle?(_uri, url) do String.match?(url, @url_regex) end + @spec scrape(URI.t(), Scrapers.url()) :: Scrapers.scrape_result() def scrape(_uri, url) do [user, status_id] = Regex.run(@url_regex, url, capture: :all_but_first) api_url = "https://api.fxtwitter.com/#{user}/status/#{status_id}" - {:ok, %Tesla.Env{status: 200, body: body}} = Philomena.Http.get(api_url) + {:ok, %Tesla.Env{status: 200, body: body}} = PhilomenaProxy.Http.get(api_url) json = Jason.decode!(body) tweet = json["tweet"] @@ -19,7 +27,7 @@ defmodule Philomena.Scrapers.Twitter do Enum.map(tweet["media"]["photos"], fn p -> %{ url: "#{p["url"]}:orig", - camo_url: Camo.Image.image_url(p["url"]) + camo_url: PhilomenaProxy.Camo.image_url(p["url"]) } end) diff --git a/lib/philomena_web/controllers/image/scrape_controller.ex b/lib/philomena_web/controllers/image/scrape_controller.ex index a46c8733..56e602e9 100644 --- a/lib/philomena_web/controllers/image/scrape_controller.ex +++ b/lib/philomena_web/controllers/image/scrape_controller.ex @@ -1,7 +1,7 @@ defmodule PhilomenaWeb.Image.ScrapeController do use PhilomenaWeb, :controller - alias Philomena.Scrapers + alias PhilomenaProxy.Scrapers def create(conn, params) do result = diff --git a/lib/philomena_web/plugs/check_captcha_plug.ex b/lib/philomena_web/plugs/check_captcha_plug.ex index d411d405..607309ad 100644 --- a/lib/philomena_web/plugs/check_captcha_plug.ex +++ b/lib/philomena_web/plugs/check_captcha_plug.ex @@ -31,7 +31,7 @@ defmodule PhilomenaWeb.CheckCaptchaPlug do defp valid_solution?(%{"h-captcha-response" => captcha_token}) do {:ok, %{body: body, status: 200}} = - Philomena.Http.post( + PhilomenaProxy.Http.post( "https://hcaptcha.com/siteverify", URI.encode_query(%{"response" => captcha_token, "secret" => hcaptcha_secret_key()}), [{"Content-Type", "application/x-www-form-urlencoded"}] diff --git a/lib/philomena_web/plugs/compromised_password_check_plug.ex b/lib/philomena_web/plugs/compromised_password_check_plug.ex index eaeecd2a..b46e597f 100644 --- a/lib/philomena_web/plugs/compromised_password_check_plug.ex +++ b/lib/philomena_web/plugs/compromised_password_check_plug.ex @@ -35,7 +35,7 @@ defmodule PhilomenaWeb.CompromisedPasswordCheckPlug do :crypto.hash(:sha, password) |> Base.encode16() - case Philomena.Http.get(make_api_url(prefix)) do + case PhilomenaProxy.Http.get(make_api_url(prefix)) do {:ok, %Tesla.Env{body: body, status: 200}} -> String.contains?(body, rest) _ -> false end diff --git a/lib/philomena_web/plugs/scraper_plug.ex b/lib/philomena_web/plugs/scraper_plug.ex index 1fcd0db1..2e4e1769 100644 --- a/lib/philomena_web/plugs/scraper_plug.ex +++ b/lib/philomena_web/plugs/scraper_plug.ex @@ -15,7 +15,7 @@ defmodule PhilomenaWeb.ScraperPlug do %{"scraper_cache" => url} when not is_nil(url) and url != "" -> url - |> Philomena.Http.get() + |> PhilomenaProxy.Http.get() |> maybe_fixup_params(url, opts, conn) _ -> diff --git a/lib/philomena_web/views/channel_view.ex b/lib/philomena_web/views/channel_view.ex index b4dc532e..acb4880a 100644 --- a/lib/philomena_web/views/channel_view.ex +++ b/lib/philomena_web/views/channel_view.ex @@ -4,20 +4,24 @@ defmodule PhilomenaWeb.ChannelView do def channel_image(%{type: "LivestreamChannel", short_name: short_name}) do now = DateTime.utc_now() |> DateTime.to_unix(:microsecond) - Camo.Image.image_url( + PhilomenaProxy.Camo.image_url( "https://thumbnail.api.livestream.com/thumbnail?name=#{short_name}&rand=#{now}" ) end def channel_image(%{type: "PicartoChannel", thumbnail_url: thumbnail_url}), - do: Camo.Image.image_url(thumbnail_url || "https://picarto.tv/images/missingthumb.jpg") + do: + PhilomenaProxy.Camo.image_url(thumbnail_url || "https://picarto.tv/images/missingthumb.jpg") def channel_image(%{type: "PiczelChannel", remote_stream_id: remote_stream_id}), - do: Camo.Image.image_url("https://piczel.tv/api/thumbnail/stream_#{remote_stream_id}.jpg") + do: + PhilomenaProxy.Camo.image_url( + "https://piczel.tv/api/thumbnail/stream_#{remote_stream_id}.jpg" + ) def channel_image(%{type: "TwitchChannel", short_name: short_name}), do: - Camo.Image.image_url( + PhilomenaProxy.Camo.image_url( "https://static-cdn.jtvnw.net/previews-ttv/live_user_#{String.downcase(short_name)}-320x180.jpg" ) end diff --git a/priv/repo/seeds_development.exs b/priv/repo/seeds_development.exs index 466b3111..cde0302a 100644 --- a/priv/repo/seeds_development.exs +++ b/priv/repo/seeds_development.exs @@ -52,7 +52,7 @@ for image_def <- resources["remote_images"] do now = DateTime.utc_now() |> DateTime.to_unix(:microsecond) IO.puts "Fetching #{image_def["url"]} ..." - {:ok, %{body: body}} = Philomena.Http.get(image_def["url"]) + {:ok, %{body: body}} = PhilomenaProxy.Http.get(image_def["url"]) File.write!(file, body) From 410332003b34cd25910ff66fdc970cdef99e1bcd Mon Sep 17 00:00:00 2001 From: Liam Date: Sun, 2 Jun 2024 22:48:24 -0400 Subject: [PATCH 24/35] Use decimal parsing for search dist value --- lib/philomena_web/image_reverse.ex | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/philomena_web/image_reverse.ex b/lib/philomena_web/image_reverse.ex index e1d78a50..4fa5f459 100644 --- a/lib/philomena_web/image_reverse.ex +++ b/lib/philomena_web/image_reverse.ex @@ -44,10 +44,20 @@ defmodule PhilomenaWeb.ImageReverse do # because this is more efficient to index. defp normalize_dist(%{"distance" => distance}) do distance - |> String.to_float() + |> parse_dist() |> max(0.01) |> min(1.0) end defp normalize_dist(_dist), do: 0.25 + + defp parse_dist(dist) do + case Decimal.parse(dist) do + {value, _rest} -> + Decimal.to_float(value) + + _ -> + 0.0 + end + end end From f92b61c176b21807fd11eb03165bc0a5944090b7 Mon Sep 17 00:00:00 2001 From: Liam Date: Sun, 2 Jun 2024 22:58:09 -0400 Subject: [PATCH 25/35] Add missing constraint conversions for interaction tables --- lib/philomena/image_faves/image_fave.ex | 1 + lib/philomena/image_hides/image_hide.ex | 1 + lib/philomena/image_votes/image_vote.ex | 1 + 3 files changed, 3 insertions(+) diff --git a/lib/philomena/image_faves/image_fave.ex b/lib/philomena/image_faves/image_fave.ex index 50b7b49a..cb99472d 100644 --- a/lib/philomena/image_faves/image_fave.ex +++ b/lib/philomena/image_faves/image_fave.ex @@ -18,5 +18,6 @@ defmodule Philomena.ImageFaves.ImageFave do image_fave |> cast(attrs, []) |> validate_required([]) + |> unique_constraint([:image_id, :user_id], name: :index_image_faves_on_image_id_and_user_id) end end diff --git a/lib/philomena/image_hides/image_hide.ex b/lib/philomena/image_hides/image_hide.ex index bc52bb8d..e60d12d5 100644 --- a/lib/philomena/image_hides/image_hide.ex +++ b/lib/philomena/image_hides/image_hide.ex @@ -18,5 +18,6 @@ defmodule Philomena.ImageHides.ImageHide do image_hide |> cast(attrs, []) |> validate_required([]) + |> unique_constraint([:image_id, :user_id], name: :index_image_hides_on_image_id_and_user_id) end end diff --git a/lib/philomena/image_votes/image_vote.ex b/lib/philomena/image_votes/image_vote.ex index d3dd1689..eeb8c953 100644 --- a/lib/philomena/image_votes/image_vote.ex +++ b/lib/philomena/image_votes/image_vote.ex @@ -19,5 +19,6 @@ defmodule Philomena.ImageVotes.ImageVote do image_vote |> cast(attrs, []) |> validate_required([]) + |> unique_constraint([:image_id, :user_id], name: :index_image_votes_on_image_id_and_user_id) end end From 9122ba0829d9ada8ab1fb889652805acc3e6a0e9 Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 3 Jun 2024 09:35:44 -0400 Subject: [PATCH 26/35] Missing static paths --- lib/philomena_web.ex | 2 +- lib/philomena_web/templates/layout/app.html.slime | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/philomena_web.ex b/lib/philomena_web.ex index fd16f8ce..eaa5a76a 100644 --- a/lib/philomena_web.ex +++ b/lib/philomena_web.ex @@ -17,7 +17,7 @@ defmodule PhilomenaWeb do and import those modules here. """ - def static_paths, do: ~w(assets favicon.ico favicon.svg robots.txt opensearch.xml) + def static_paths, do: ~w(assets css js favicon.ico favicon.svg robots.txt opensearch.xml) def controller do quote do diff --git a/lib/philomena_web/templates/layout/app.html.slime b/lib/philomena_web/templates/layout/app.html.slime index d7842369..227432e7 100644 --- a/lib/philomena_web/templates/layout/app.html.slime +++ b/lib/philomena_web/templates/layout/app.html.slime @@ -13,9 +13,9 @@ html lang="en" link rel="stylesheet" href=stylesheet_path(@current_user) = if is_nil(@current_user) do link rel="stylesheet" href=dark_stylesheet_path() media="(prefers-color-scheme: dark)" - link rel="icon" href=~p"/favicon.ico" type="image/x-icon" - link rel="icon" href=~p"/favicon.svg" type="image/svg+xml" - link rel="search" type="application/opensearchdescription+xml" title="Derpibooru" href=~p"/opensearch.xml" + link rel="icon" href="/favicon.ico" type="image/x-icon" + link rel="icon" href="/favicon.svg" type="image/svg+xml" + link rel="search" type="application/opensearchdescription+xml" title="Derpibooru" href="/opensearch.xml" meta name="generator" content="philomena" meta name="theme-color" content="#618fc3" meta name="format-detection" content="telephone=no" From 8d2c0824133ad13fc02418b9aa1a25cfa6c52bd5 Mon Sep 17 00:00:00 2001 From: KoloMl Date: Mon, 3 Jun 2024 17:48:42 +0400 Subject: [PATCH 27/35] Disable server-side autocompletion when `acSource` is not set --- assets/js/autocomplete.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/assets/js/autocomplete.js b/assets/js/autocomplete.js index 978c7cab..758754dd 100644 --- a/assets/js/autocomplete.js +++ b/assets/js/autocomplete.js @@ -171,6 +171,8 @@ function showAutocomplete(suggestions, fetchedTerm, targetInput) { } function getSuggestions(term) { + // In case source URL was not given at all, do not try sending the request. + if (!inputField.dataset.acSource) return []; return fetch(`${inputField.dataset.acSource}${term}`).then(response => response.json()); } @@ -241,9 +243,9 @@ function listenAutocomplete() { originalTerm = inputField.value; const fetchedTerm = inputField.value; - const {ac, acMinLength} = inputField.dataset; + const {ac, acMinLength, acSource} = inputField.dataset; - if (ac && (fetchedTerm.length >= acMinLength)) { + if (ac && acSource && (fetchedTerm.length >= acMinLength)) { if (cache[fetchedTerm]) { showAutocomplete(cache[fetchedTerm], fetchedTerm, event.target); } From ac12837941a675d82ae0323ce2e44a411e2c5bdf Mon Sep 17 00:00:00 2001 From: KoloMl Date: Mon, 3 Jun 2024 17:49:01 +0400 Subject: [PATCH 28/35] Disable server-side autocompletion for search field --- lib/philomena_web/templates/layout/_header.html.slime | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/philomena_web/templates/layout/_header.html.slime b/lib/philomena_web/templates/layout/_header.html.slime index 9a4d4125..60aa3b6f 100644 --- a/lib/philomena_web/templates/layout/_header.html.slime +++ b/lib/philomena_web/templates/layout/_header.html.slime @@ -12,7 +12,7 @@ header.header i.fa.fa-upload = form_for @conn, ~p"/search", [method: "get", class: "header__search flex flex--no-wrap flex--centered", enforce_utf8: false], fn f -> - input.input.header__input.header__input--search#q name="q" title="For terms all required, separate with ',' or 'AND'; also supports 'OR' for optional terms and '-' or 'NOT' for negation. Search with a blank query for more options or click the ? for syntax help." value=@conn.params["q"] placeholder="Search" autocapitalize="none" autocomplete="off" data-ac="true" data-ac-min-length="3" data-ac-source="/autocomplete/tags?term=" data-ac-mode="search" + input.input.header__input.header__input--search#q name="q" title="For terms all required, separate with ',' or 'AND'; also supports 'OR' for optional terms and '-' or 'NOT' for negation. Search with a blank query for more options or click the ? for syntax help." value=@conn.params["q"] placeholder="Search" autocapitalize="none" autocomplete="off" data-ac="true" data-ac-min-length="3" data-ac-mode="search" = if present?(@conn.params["sf"]) do input type="hidden" name="sf" value=@conn.params["sf"] From 961c9998b8d4d9148f6dee8c69e6e54053994e09 Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 3 Jun 2024 10:12:42 -0400 Subject: [PATCH 29/35] Add missing constraint conversion to artist links --- lib/philomena/artist_links/artist_link.ex | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/philomena/artist_links/artist_link.ex b/lib/philomena/artist_links/artist_link.ex index b8878951..4116e5e3 100644 --- a/lib/philomena/artist_links/artist_link.ex +++ b/lib/philomena/artist_links/artist_link.ex @@ -58,6 +58,9 @@ defmodule Philomena.ArtistLinks.ArtistLink do |> parse_uri() |> put_verification_code() |> put_next_check_at() + |> unique_constraint([:uri, :tag_id, :user_id], + name: :index_artist_links_on_uri_tag_id_user_id + ) end def validate_category(changeset) do From f44491685ebec254f3051310bbede662c4b5ba2e Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 3 Jun 2024 10:59:49 -0400 Subject: [PATCH 30/35] Disable search completion by default, use setting to enable --- assets/js/autocomplete.js | 11 ++++++++--- lib/philomena_web/controllers/setting_controller.ex | 2 +- lib/philomena_web/templates/layout/_header.html.slime | 2 +- lib/philomena_web/templates/setting/edit.html.slime | 6 +++--- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/assets/js/autocomplete.js b/assets/js/autocomplete.js index 758754dd..1b7c6fd8 100644 --- a/assets/js/autocomplete.js +++ b/assets/js/autocomplete.js @@ -188,11 +188,16 @@ function getSelectedTerm() { } function toggleSearchAutocomplete() { - if (!store.get('disable_search_ac')) return; + const enable = store.get('enable_search_ac'); for (const searchField of document.querySelectorAll('input[data-ac-mode=search]')) { - searchField.removeAttribute('data-ac'); - searchField.autocomplete = 'on'; + if (enable) { + searchField.autocomplete = 'off'; + } + else { + searchField.removeAttribute('data-ac'); + searchField.autocomplete = 'on'; + } } } diff --git a/lib/philomena_web/controllers/setting_controller.ex b/lib/philomena_web/controllers/setting_controller.ex index e9241d1c..64118a45 100644 --- a/lib/philomena_web/controllers/setting_controller.ex +++ b/lib/philomena_web/controllers/setting_controller.ex @@ -45,7 +45,7 @@ defmodule PhilomenaWeb.SettingController do |> set_cookie(user_params, "hide_uploader", "hide_uploader") |> set_cookie(user_params, "hide_score", "hide_score") |> set_cookie(user_params, "unfilter_tag_suggestions", "unfilter_tag_suggestions") - |> set_cookie(user_params, "disable_search_ac", "disable_search_ac") + |> set_cookie(user_params, "enable_search_ac", "enable_search_ac") end defp set_cookie(conn, params, param_name, cookie_name) do diff --git a/lib/philomena_web/templates/layout/_header.html.slime b/lib/philomena_web/templates/layout/_header.html.slime index 60aa3b6f..0cf9fc2e 100644 --- a/lib/philomena_web/templates/layout/_header.html.slime +++ b/lib/philomena_web/templates/layout/_header.html.slime @@ -12,7 +12,7 @@ header.header i.fa.fa-upload = form_for @conn, ~p"/search", [method: "get", class: "header__search flex flex--no-wrap flex--centered", enforce_utf8: false], fn f -> - input.input.header__input.header__input--search#q name="q" title="For terms all required, separate with ',' or 'AND'; also supports 'OR' for optional terms and '-' or 'NOT' for negation. Search with a blank query for more options or click the ? for syntax help." value=@conn.params["q"] placeholder="Search" autocapitalize="none" autocomplete="off" data-ac="true" data-ac-min-length="3" data-ac-mode="search" + input.input.header__input.header__input--search#q name="q" title="For terms all required, separate with ',' or 'AND'; also supports 'OR' for optional terms and '-' or 'NOT' for negation. Search with a blank query for more options or click the ? for syntax help." value=@conn.params["q"] placeholder="Search" autocapitalize="none" data-ac="true" data-ac-min-length="3" data-ac-mode="search" = if present?(@conn.params["sf"]) do input type="hidden" name="sf" value=@conn.params["sf"] diff --git a/lib/philomena_web/templates/setting/edit.html.slime b/lib/philomena_web/templates/setting/edit.html.slime index a61d6307..d2ef4027 100644 --- a/lib/philomena_web/templates/setting/edit.html.slime +++ b/lib/philomena_web/templates/setting/edit.html.slime @@ -175,9 +175,9 @@ h1 Content Settings => checkbox f, :chan_nsfw, checked: @conn.cookies["chan_nsfw"] == "true" .fieldlabel: i Show streams marked as NSFW on the channels page. .field - => label f, :disable_search_ac, "Disable search auto-completion" - => checkbox f, :disable_search_ac, checked: @conn.cookies["disable_search_ac"] === "true" - .fieldlabel: i Disable the auto-completion of tags in the search fields. This will bring back default browser's behaviour. + => label f, :enable_search_ac, "Enable search auto-completion" + => checkbox f, :enable_search_ac, checked: @conn.cookies["enable_search_ac"] === "true" + .fieldlabel: i Enable the auto-completion of tags in search fields. = if staff?(@conn.assigns.current_user) do .field => label f, :hide_staff_tools From c50abd597f3559a437f22d060e87874513d05b6b Mon Sep 17 00:00:00 2001 From: KoloMl Date: Mon, 3 Jun 2024 21:35:18 +0400 Subject: [PATCH 31/35] Fixed z-index position of the autocomplete list --- assets/css/views/_tags.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/assets/css/views/_tags.scss b/assets/css/views/_tags.scss index 6626dda4..331ff13d 100644 --- a/assets/css/views/_tags.scss +++ b/assets/css/views/_tags.scss @@ -43,6 +43,7 @@ position: absolute; user-select: none; white-space: nowrap; + z-index: 999; } .autocomplete__item { From 0381409862ba8d9ac767ccdad787fd88407f0191 Mon Sep 17 00:00:00 2001 From: KoloMl Date: Mon, 3 Jun 2024 21:42:58 +0400 Subject: [PATCH 32/35] Lowercasing term before running the auto-completion on it --- assets/js/autocomplete.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/js/autocomplete.js b/assets/js/autocomplete.js index 1b7c6fd8..1551a6f8 100644 --- a/assets/js/autocomplete.js +++ b/assets/js/autocomplete.js @@ -229,7 +229,7 @@ function listenAutocomplete() { return; } - originalTerm = selectedTerm[1]; + originalTerm = selectedTerm[1].toLowerCase(); } else { originalTerm = `${inputField.value}`.toLowerCase(); From 566ba9d4c1c0e62803040dd728a51d8cb6ba3900 Mon Sep 17 00:00:00 2001 From: Liam Date: Sat, 25 May 2024 14:03:45 -0400 Subject: [PATCH 33/35] Split out query features to PhilomenaQuery namespace --- README.md | 2 +- docker/app/run-test | 4 +- lib/mix/tasks/reindex_all.ex | 16 +- lib/mix/tasks/upload_to_s3.ex | 2 +- lib/philomena/batch.ex | 56 -- lib/philomena/comments.ex | 8 +- lib/philomena/comments/query.ex | 2 +- ...elasticsearch_index.ex => search_index.ex} | 4 +- lib/philomena/elasticsearch.ex | 294 -------- lib/philomena/filters.ex | 10 +- lib/philomena/filters/query.ex | 2 +- ...elasticsearch_index.ex => search_index.ex} | 4 +- lib/philomena/galleries.ex | 10 +- lib/philomena/galleries/query.ex | 2 +- ...elasticsearch_index.ex => search_index.ex} | 4 +- lib/philomena/images.ex | 8 +- lib/philomena/images/query.ex | 4 +- ...elasticsearch_index.ex => search_index.ex} | 4 +- lib/philomena/posts.ex | 8 +- lib/philomena/posts/query.ex | 2 +- ...elasticsearch_index.ex => search_index.ex} | 4 +- lib/philomena/reports.ex | 8 +- lib/philomena/reports/query.ex | 2 +- ...elasticsearch_index.ex => search_index.ex} | 4 +- lib/philomena/schema/search.ex | 2 +- lib/philomena/schema/time.ex | 2 +- lib/philomena/search/string.ex | 13 - lib/philomena/tags.ex | 12 +- lib/philomena/tags/query.ex | 2 +- ...elasticsearch_index.ex => search_index.ex} | 4 +- lib/philomena/user_downvote_wipe.ex | 6 +- lib/philomena/workers/index_worker.ex | 2 +- .../workers/tag_change_revert_worker.ex | 2 +- lib/philomena_query/batch.ex | 111 +++ .../parse}/bool_parser.ex | 4 +- .../parse}/date_parser.ex | 10 +- .../parse}/evaluator.ex | 25 +- .../parse}/float_parser.ex | 8 +- .../parse}/helpers.ex | 4 +- .../parse}/int_parser.ex | 8 +- .../parse}/ip_parser.ex | 4 +- .../search => philomena_query/parse}/lexer.ex | 6 +- .../parse}/literal_parser.ex | 6 +- .../parse}/ngram_parser.ex | 6 +- .../parse}/parser.ex | 117 +++- lib/philomena_query/parse/string.ex | 32 + .../parse}/term_range_parser.ex | 8 +- .../relative_date.ex | 48 +- lib/philomena_query/search.ex | 654 ++++++++++++++++++ .../search_index.ex} | 5 +- .../controllers/activity_controller.ex | 8 +- .../controllers/admin/report_controller.ex | 6 +- .../api/json/search/comment_controller.ex | 6 +- .../api/json/search/filter_controller.ex | 6 +- .../api/json/search/gallery_controller.ex | 6 +- .../api/json/search/image_controller.ex | 4 +- .../api/json/search/post_controller.ex | 6 +- .../api/json/search/tag_controller.ex | 6 +- .../controllers/api/rss/watched_controller.ex | 4 +- .../autocomplete/tag_controller.ex | 6 +- .../controllers/comment_controller.ex | 6 +- .../controllers/filter_controller.ex | 6 +- .../controllers/gallery_controller.ex | 12 +- .../controllers/image/navigate_controller.ex | 4 +- .../controllers/image/random_controller.ex | 4 +- .../controllers/image/related_controller.ex | 4 +- .../controllers/image_controller.ex | 4 +- .../controllers/post_controller.ex | 6 +- .../controllers/profile_controller.ex | 10 +- .../controllers/search_controller.ex | 6 +- .../controllers/tag_controller.ex | 8 +- lib/philomena_web/image_loader.ex | 4 +- lib/philomena_web/image_navigator.ex | 6 +- .../plugs/filter_forced_users_plug.ex | 4 +- lib/philomena_web/plugs/image_filter_plug.ex | 2 +- lib/philomena_web/stats_updater.ex | 6 +- .../views/api/json/image_view.ex | 2 +- lib/philomena_web/views/image_view.ex | 2 +- lib/philomena_web/views/layout_view.ex | 4 +- lib/philomena_web/views/tag_view.ex | 6 +- priv/repo/seeds.exs | 10 +- 81 files changed, 1185 insertions(+), 554 deletions(-) delete mode 100644 lib/philomena/batch.ex rename lib/philomena/comments/{elasticsearch_index.ex => search_index.ex} (94%) delete mode 100644 lib/philomena/elasticsearch.ex rename lib/philomena/filters/{elasticsearch_index.ex => search_index.ex} (95%) rename lib/philomena/galleries/{elasticsearch_index.ex => search_index.ex} (94%) rename lib/philomena/images/{elasticsearch_index.ex => search_index.ex} (98%) rename lib/philomena/posts/{elasticsearch_index.ex => search_index.ex} (96%) rename lib/philomena/reports/{elasticsearch_index.ex => search_index.ex} (96%) delete mode 100644 lib/philomena/search/string.ex rename lib/philomena/tags/{elasticsearch_index.ex => search_index.ex} (95%) create mode 100644 lib/philomena_query/batch.ex rename lib/{philomena/search => philomena_query/parse}/bool_parser.ex (84%) rename lib/{philomena/search => philomena_query/parse}/date_parser.ex (96%) rename lib/{philomena/search => philomena_query/parse}/evaluator.ex (90%) rename lib/{philomena/search => philomena_query/parse}/float_parser.ex (81%) rename lib/{philomena/search => philomena_query/parse}/helpers.ex (90%) rename lib/{philomena/search => philomena_query/parse}/int_parser.ex (75%) rename lib/{philomena/search => philomena_query/parse}/ip_parser.ex (98%) rename lib/{philomena/search => philomena_query/parse}/lexer.ex (94%) rename lib/{philomena/search => philomena_query/parse}/literal_parser.ex (89%) rename lib/{philomena/search => philomena_query/parse}/ngram_parser.ex (51%) rename lib/{philomena/search => philomena_query/parse}/parser.ex (73%) create mode 100644 lib/philomena_query/parse/string.ex rename lib/{philomena/search => philomena_query/parse}/term_range_parser.ex (90%) rename lib/{philomena => philomena_query}/relative_date.ex (63%) create mode 100644 lib/philomena_query/search.ex rename lib/{philomena/elasticsearch_index.ex => philomena_query/search_index.ex} (66%) diff --git a/README.md b/README.md index 2cf81be3..966d5e06 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Once the application has started, navigate to http://localhost:8080 and login wi If you are running Docker on Windows and the application crashes immediately upon startup, please ensure that `autocrlf` is set to `false` in your Git config, and then re-clone the repository. Additionally, it is recommended that you allocate at least 4GB of RAM to your Docker VM. -If you run into an Elasticsearch bootstrap error, you may need to increase your `max_map_count` on the host as follows: +If you run into an OpenSearch bootstrap error, you may need to increase your `max_map_count` on the host as follows: ``` sudo sysctl -w vm.max_map_count=262144 ``` diff --git a/docker/app/run-test b/docker/app/run-test index 679a438c..e55fa838 100755 --- a/docker/app/run-test +++ b/docker/app/run-test @@ -5,9 +5,9 @@ export MIX_ENV=test # Always install mix dependencies (cd /srv/philomena && mix deps.get) -# Sleep to allow Elasticsearch to finish initializing +# Sleep to allow OpenSearch to finish initializing # if it's not done doing whatever it does yet -echo -n "Waiting for Elasticsearch" +echo -n "Waiting for OpenSearch" until wget -qO - opensearch:9200; do echo -n "." diff --git a/lib/mix/tasks/reindex_all.ex b/lib/mix/tasks/reindex_all.ex index 7208c27a..c1f24114 100644 --- a/lib/mix/tasks/reindex_all.ex +++ b/lib/mix/tasks/reindex_all.ex @@ -1,7 +1,7 @@ defmodule Mix.Tasks.ReindexAll do use Mix.Task - alias Philomena.Elasticsearch + alias PhilomenaQuery.Search alias Philomena.{ Comments.Comment, @@ -27,7 +27,7 @@ defmodule Mix.Tasks.ReindexAll do {Filters, Filter} ] - @shortdoc "Destroys and recreates all Elasticsearch indices." + @shortdoc "Destroys and recreates all OpenSearch indices." @requirements ["app.start"] @impl Mix.Task def run(args) do @@ -38,23 +38,23 @@ defmodule Mix.Tasks.ReindexAll do @indices |> Enum.map(fn {context, schema} -> Task.async(fn -> - Elasticsearch.delete_index!(schema) - Elasticsearch.create_index!(schema) + Search.delete_index!(schema) + Search.create_index!(schema) - Elasticsearch.reindex(preload(schema, ^context.indexing_preloads()), schema) + Search.reindex(preload(schema, ^context.indexing_preloads()), schema) end) end) |> Task.await_many(:infinity) # Reports are a bit special - Elasticsearch.delete_index!(Report) - Elasticsearch.create_index!(Report) + Search.delete_index!(Report) + Search.create_index!(Report) Report |> preload([:user, :admin]) |> Repo.all() |> Polymorphic.load_polymorphic(reportable: [reportable_id: :reportable_type]) - |> Enum.map(&Elasticsearch.index_document(&1, Report)) + |> Enum.map(&Search.index_document(&1, Report)) end end diff --git a/lib/mix/tasks/upload_to_s3.ex b/lib/mix/tasks/upload_to_s3.ex index 0155514f..ae6b22fd 100644 --- a/lib/mix/tasks/upload_to_s3.ex +++ b/lib/mix/tasks/upload_to_s3.ex @@ -11,7 +11,7 @@ defmodule Mix.Tasks.UploadToS3 do alias Philomena.Images.Thumbnailer alias Philomena.Objects - alias Philomena.Batch + alias PhilomenaQuery.Batch import Ecto.Query @shortdoc "Dumps existing image files to S3 storage backend" diff --git a/lib/philomena/batch.ex b/lib/philomena/batch.ex deleted file mode 100644 index 29d03582..00000000 --- a/lib/philomena/batch.ex +++ /dev/null @@ -1,56 +0,0 @@ -defmodule Philomena.Batch do - alias Philomena.Repo - import Ecto.Query - - @doc """ - Load records from the given queryable in batches, to avoid locking. - - Valid options: - * :batch_size - * :id_field - """ - def record_batches(queryable, opts \\ [], callback) do - query_batches(queryable, opts, &callback.(Repo.all(&1))) - end - - @doc """ - Load queries from the given queryable in batches, to avoid locking. - - Valid options: - * :batch_size - * :id_field - """ - def query_batches(queryable, opts \\ [], callback) do - ids = load_ids(queryable, -1, opts) - - query_batches(queryable, opts, callback, ids) - end - - defp query_batches(_queryable, _opts, _callback, []), do: [] - - defp query_batches(queryable, opts, callback, ids) do - id_field = Keyword.get(opts, :id_field, :id) - - queryable - |> where([m], field(m, ^id_field) in ^ids) - |> callback.() - - ids = load_ids(queryable, Enum.max(ids), opts) - - query_batches(queryable, opts, callback, ids) - end - - defp load_ids(queryable, max_id, opts) do - id_field = Keyword.get(opts, :id_field, :id) - batch_size = Keyword.get(opts, :batch_size, 1000) - - queryable - |> exclude(:preload) - |> exclude(:order_by) - |> order_by(asc: ^id_field) - |> where([m], field(m, ^id_field) > ^max_id) - |> select([m], field(m, ^id_field)) - |> limit(^batch_size) - |> Repo.all() - end -end diff --git a/lib/philomena/comments.ex b/lib/philomena/comments.ex index b353a181..1d606ff0 100644 --- a/lib/philomena/comments.ex +++ b/lib/philomena/comments.ex @@ -7,11 +7,11 @@ defmodule Philomena.Comments do alias Ecto.Multi alias Philomena.Repo - alias Philomena.Elasticsearch + alias PhilomenaQuery.Search alias Philomena.Reports.Report alias Philomena.UserStatistics alias Philomena.Comments.Comment - alias Philomena.Comments.ElasticsearchIndex, as: CommentIndex + alias Philomena.Comments.SearchIndex, as: CommentIndex alias Philomena.IndexWorker alias Philomena.Images.Image alias Philomena.Images @@ -265,7 +265,7 @@ defmodule Philomena.Comments do def user_name_reindex(old_name, new_name) do data = CommentIndex.user_name_update_by_query(old_name, new_name) - Elasticsearch.update_by_query(Comment, data.query, data.set_replacements, data.replacements) + Search.update_by_query(Comment, data.query, data.set_replacements, data.replacements) end def reindex_comment(%Comment{} = comment) do @@ -288,6 +288,6 @@ defmodule Philomena.Comments do Comment |> preload(^indexing_preloads()) |> where([c], field(c, ^column) in ^condition) - |> Elasticsearch.reindex(Comment) + |> Search.reindex(Comment) end end diff --git a/lib/philomena/comments/query.ex b/lib/philomena/comments/query.ex index 21df1ed1..6b2bea42 100644 --- a/lib/philomena/comments/query.ex +++ b/lib/philomena/comments/query.ex @@ -1,5 +1,5 @@ defmodule Philomena.Comments.Query do - alias Philomena.Search.Parser + alias PhilomenaQuery.Parse.Parser defp user_id_transform(_ctx, data) do case Integer.parse(data) do diff --git a/lib/philomena/comments/elasticsearch_index.ex b/lib/philomena/comments/search_index.ex similarity index 94% rename from lib/philomena/comments/elasticsearch_index.ex rename to lib/philomena/comments/search_index.ex index 82d65bcc..b08b1594 100644 --- a/lib/philomena/comments/elasticsearch_index.ex +++ b/lib/philomena/comments/search_index.ex @@ -1,5 +1,5 @@ -defmodule Philomena.Comments.ElasticsearchIndex do - @behaviour Philomena.ElasticsearchIndex +defmodule Philomena.Comments.SearchIndex do + @behaviour PhilomenaQuery.SearchIndex @impl true def index_name do diff --git a/lib/philomena/elasticsearch.ex b/lib/philomena/elasticsearch.ex deleted file mode 100644 index a85bfc50..00000000 --- a/lib/philomena/elasticsearch.ex +++ /dev/null @@ -1,294 +0,0 @@ -defmodule Philomena.Elasticsearch do - alias Philomena.Batch - alias Philomena.Repo - require Logger - import Ecto.Query - import Elastix.HTTP - - alias Philomena.Comments.Comment - alias Philomena.Galleries.Gallery - alias Philomena.Images.Image - alias Philomena.Posts.Post - alias Philomena.Reports.Report - alias Philomena.Tags.Tag - alias Philomena.Filters.Filter - - alias Philomena.Comments.ElasticsearchIndex, as: CommentIndex - alias Philomena.Galleries.ElasticsearchIndex, as: GalleryIndex - alias Philomena.Images.ElasticsearchIndex, as: ImageIndex - alias Philomena.Posts.ElasticsearchIndex, as: PostIndex - alias Philomena.Reports.ElasticsearchIndex, as: ReportIndex - alias Philomena.Tags.ElasticsearchIndex, as: TagIndex - alias Philomena.Filters.ElasticsearchIndex, as: FilterIndex - - defp index_for(Comment), do: CommentIndex - defp index_for(Gallery), do: GalleryIndex - defp index_for(Image), do: ImageIndex - defp index_for(Post), do: PostIndex - defp index_for(Report), do: ReportIndex - defp index_for(Tag), do: TagIndex - defp index_for(Filter), do: FilterIndex - - defp elastic_url do - Application.get_env(:philomena, :opensearch_url) - end - - def create_index!(module) do - index = index_for(module) - - Elastix.Index.create( - elastic_url(), - index.index_name(), - index.mapping() - ) - end - - def delete_index!(module) do - index = index_for(module) - - Elastix.Index.delete(elastic_url(), index.index_name()) - end - - def update_mapping!(module) do - index = index_for(module) - - index_name = index.index_name() - mapping = index.mapping().mappings.properties - - Elastix.Mapping.put(elastic_url(), index_name, "_doc", %{properties: mapping}, - include_type_name: true - ) - end - - def index_document(doc, module) do - index = index_for(module) - data = index.as_json(doc) - - Elastix.Document.index( - elastic_url(), - index.index_name(), - "_doc", - data.id, - data - ) - end - - def delete_document(id, module) do - index = index_for(module) - - Elastix.Document.delete( - elastic_url(), - index.index_name(), - "_doc", - id - ) - end - - def reindex(queryable, module, opts \\ []) do - index = index_for(module) - - Batch.record_batches(queryable, opts, fn records -> - lines = - Enum.flat_map(records, fn record -> - doc = index.as_json(record) - - [ - %{index: %{_index: index.index_name(), _id: doc.id}}, - doc - ] - end) - - Elastix.Bulk.post( - elastic_url(), - lines, - index: index.index_name(), - httpoison_options: [timeout: 30_000] - ) - end) - end - - def update_by_query(module, query_body, set_replacements, replacements) do - index = index_for(module) - - url = - elastic_url() - |> prepare_url([index.index_name(), "_update_by_query"]) - |> append_query_string(%{conflicts: "proceed", wait_for_completion: "false"}) - - # Elasticsearch "Painless" scripting language - script = """ - // Replace values in "sets" (arrays in the source document) - for (int i = 0; i < params.set_replacements.length; ++i) { - def replacement = params.set_replacements[i]; - def path = replacement.path; - def old_value = replacement.old; - def new_value = replacement.new; - def reference = ctx._source; - - for (int j = 0; j < path.length; ++j) { - reference = reference[path[j]]; - } - - for (int j = 0; j < reference.length; ++j) { - if (reference[j].equals(old_value)) { - reference[j] = new_value; - } - } - } - - // Replace values in standalone fields - for (int i = 0; i < params.replacements.length; ++i) { - def replacement = params.replacements[i]; - def path = replacement.path; - def old_value = replacement.old; - def new_value = replacement.new; - def reference = ctx._source; - - // A little bit more complicated: go up to the last one before it - // so that the value can actually be replaced - - for (int j = 0; j < path.length - 1; ++j) { - reference = reference[path[j]]; - } - - if (reference[path[path.length - 1]] != null && reference[path[path.length - 1]].equals(old_value)) { - reference[path[path.length - 1]] = new_value; - } - } - """ - - body = - Jason.encode!(%{ - script: %{ - source: script, - params: %{ - set_replacements: set_replacements, - replacements: replacements - } - }, - query: query_body - }) - - {:ok, %{status_code: 200}} = Elastix.HTTP.post(url, body) - end - - def search(module, query_body) do - index = index_for(module) - - {:ok, %{body: results, status_code: 200}} = - Elastix.Search.search( - elastic_url(), - index.index_name(), - [], - query_body - ) - - results - end - - def msearch(definitions) do - msearch_body = - Enum.flat_map(definitions, fn def -> - [ - %{index: index_for(def.module).index_name()}, - def.body - ] - end) - - {:ok, %{body: results, status_code: 200}} = - Elastix.Search.search( - elastic_url(), - "_all", - [], - msearch_body - ) - - results["responses"] - end - - def search_definition(module, elastic_query, pagination_params \\ %{}) do - page_number = pagination_params[:page_number] || 1 - page_size = pagination_params[:page_size] || 25 - - elastic_query = - Map.merge(elastic_query, %{ - from: (page_number - 1) * page_size, - size: page_size, - _source: false, - track_total_hits: true - }) - - %{ - module: module, - body: elastic_query, - page_number: page_number, - page_size: page_size - } - end - - defp process_results(results, definition) do - time = results["took"] - count = results["hits"]["total"]["value"] - entries = Enum.map(results["hits"]["hits"], &{String.to_integer(&1["_id"]), &1}) - - Logger.debug("[Elasticsearch] Query took #{time}ms") - Logger.debug("[Elasticsearch] #{Jason.encode!(definition.body)}") - - %Scrivener.Page{ - entries: entries, - page_number: definition.page_number, - page_size: definition.page_size, - total_entries: count, - total_pages: div(count + definition.page_size - 1, definition.page_size) - } - end - - def search_results(definition) do - process_results(search(definition.module, definition.body), definition) - end - - def msearch_results(definitions) do - Enum.map(Enum.zip(msearch(definitions), definitions), fn {result, definition} -> - process_results(result, definition) - end) - end - - defp load_records_from_results(results, ecto_queries) do - Enum.map(Enum.zip(results, ecto_queries), fn {page, ecto_query} -> - {ids, hits} = Enum.unzip(page.entries) - - records = - ecto_query - |> where([m], m.id in ^ids) - |> Repo.all() - |> Enum.sort_by(&Enum.find_index(ids, fn el -> el == &1.id end)) - - %{page | entries: Enum.zip(records, hits)} - end) - end - - def search_records_with_hits(definition, ecto_query) do - [page] = load_records_from_results([search_results(definition)], [ecto_query]) - - page - end - - def msearch_records_with_hits(definitions, ecto_queries) do - load_records_from_results(msearch_results(definitions), ecto_queries) - end - - def search_records(definition, ecto_query) do - page = search_records_with_hits(definition, ecto_query) - {records, _hits} = Enum.unzip(page.entries) - - %{page | entries: records} - end - - def msearch_records(definitions, ecto_queries) do - Enum.map(load_records_from_results(msearch_results(definitions), ecto_queries), fn page -> - {records, _hits} = Enum.unzip(page.entries) - - %{page | entries: records} - end) - end -end diff --git a/lib/philomena/filters.ex b/lib/philomena/filters.ex index 363926f9..6ff7daa4 100644 --- a/lib/philomena/filters.ex +++ b/lib/philomena/filters.ex @@ -7,8 +7,8 @@ defmodule Philomena.Filters do alias Philomena.Repo alias Philomena.Filters.Filter - alias Philomena.Elasticsearch - alias Philomena.Filters.ElasticsearchIndex, as: FilterIndex + alias PhilomenaQuery.Search + alias Philomena.Filters.SearchIndex, as: FilterIndex alias Philomena.IndexWorker @doc """ @@ -223,7 +223,7 @@ defmodule Philomena.Filters do def user_name_reindex(old_name, new_name) do data = FilterIndex.user_name_update_by_query(old_name, new_name) - Elasticsearch.update_by_query(Filter, data.query, data.set_replacements, data.replacements) + Search.update_by_query(Filter, data.query, data.set_replacements, data.replacements) end def reindex_filter(%Filter{} = filter) do @@ -233,7 +233,7 @@ defmodule Philomena.Filters do end def unindex_filter(%Filter{} = filter) do - Elasticsearch.delete_document(filter.id, Filter) + Search.delete_document(filter.id, Filter) filter end @@ -246,6 +246,6 @@ defmodule Philomena.Filters do Filter |> preload(^indexing_preloads()) |> where([f], field(f, ^column) in ^condition) - |> Elasticsearch.reindex(Filter) + |> Search.reindex(Filter) end end diff --git a/lib/philomena/filters/query.ex b/lib/philomena/filters/query.ex index d5cc0e4e..adf53b09 100644 --- a/lib/philomena/filters/query.ex +++ b/lib/philomena/filters/query.ex @@ -1,5 +1,5 @@ defmodule Philomena.Filters.Query do - alias Philomena.Search.Parser + alias PhilomenaQuery.Parse.Parser defp user_my_transform(%{user: %{id: id}}, "filters"), do: {:ok, %{term: %{user_id: id}}} diff --git a/lib/philomena/filters/elasticsearch_index.ex b/lib/philomena/filters/search_index.ex similarity index 95% rename from lib/philomena/filters/elasticsearch_index.ex rename to lib/philomena/filters/search_index.ex index 94f60f15..12a59385 100644 --- a/lib/philomena/filters/elasticsearch_index.ex +++ b/lib/philomena/filters/search_index.ex @@ -1,5 +1,5 @@ -defmodule Philomena.Filters.ElasticsearchIndex do - @behaviour Philomena.ElasticsearchIndex +defmodule Philomena.Filters.SearchIndex do + @behaviour PhilomenaQuery.SearchIndex @impl true def index_name do diff --git a/lib/philomena/galleries.ex b/lib/philomena/galleries.ex index d3c060ce..b0a61bd9 100644 --- a/lib/philomena/galleries.ex +++ b/lib/philomena/galleries.ex @@ -7,10 +7,10 @@ defmodule Philomena.Galleries do alias Ecto.Multi alias Philomena.Repo - alias Philomena.Elasticsearch + alias PhilomenaQuery.Search alias Philomena.Galleries.Gallery alias Philomena.Galleries.Interaction - alias Philomena.Galleries.ElasticsearchIndex, as: GalleryIndex + alias Philomena.Galleries.SearchIndex, as: GalleryIndex alias Philomena.IndexWorker alias Philomena.GalleryReorderWorker alias Philomena.Notifications @@ -135,7 +135,7 @@ defmodule Philomena.Galleries do def user_name_reindex(old_name, new_name) do data = GalleryIndex.user_name_update_by_query(old_name, new_name) - Elasticsearch.update_by_query(Gallery, data.query, data.set_replacements, data.replacements) + Search.update_by_query(Gallery, data.query, data.set_replacements, data.replacements) end defp reindex_after_update({:ok, gallery}) do @@ -155,7 +155,7 @@ defmodule Philomena.Galleries do end def unindex_gallery(%Gallery{} = gallery) do - Elasticsearch.delete_document(gallery.id, Gallery) + Search.delete_document(gallery.id, Gallery) gallery end @@ -168,7 +168,7 @@ defmodule Philomena.Galleries do Gallery |> preload(^indexing_preloads()) |> where([g], field(g, ^column) in ^condition) - |> Elasticsearch.reindex(Gallery) + |> Search.reindex(Gallery) end def add_image_to_gallery(gallery, image) do diff --git a/lib/philomena/galleries/query.ex b/lib/philomena/galleries/query.ex index 8fd38c31..9baad469 100644 --- a/lib/philomena/galleries/query.ex +++ b/lib/philomena/galleries/query.ex @@ -1,5 +1,5 @@ defmodule Philomena.Galleries.Query do - alias Philomena.Search.Parser + alias PhilomenaQuery.Parse.Parser defp fields do [ diff --git a/lib/philomena/galleries/elasticsearch_index.ex b/lib/philomena/galleries/search_index.ex similarity index 94% rename from lib/philomena/galleries/elasticsearch_index.ex rename to lib/philomena/galleries/search_index.ex index c2071b45..37485b20 100644 --- a/lib/philomena/galleries/elasticsearch_index.ex +++ b/lib/philomena/galleries/search_index.ex @@ -1,5 +1,5 @@ -defmodule Philomena.Galleries.ElasticsearchIndex do - @behaviour Philomena.ElasticsearchIndex +defmodule Philomena.Galleries.SearchIndex do + @behaviour PhilomenaQuery.SearchIndex @impl true def index_name do diff --git a/lib/philomena/images.ex b/lib/philomena/images.ex index fe2e0ac2..95788ad5 100644 --- a/lib/philomena/images.ex +++ b/lib/philomena/images.ex @@ -9,7 +9,7 @@ defmodule Philomena.Images do alias Ecto.Multi alias Philomena.Repo - alias Philomena.Elasticsearch + alias PhilomenaQuery.Search alias Philomena.ThumbnailWorker alias Philomena.ImagePurgeWorker alias Philomena.DuplicateReports.DuplicateReport @@ -18,7 +18,7 @@ defmodule Philomena.Images do alias Philomena.Images.Tagging alias Philomena.Images.Thumbnailer alias Philomena.Images.Source - alias Philomena.Images.ElasticsearchIndex, as: ImageIndex + alias Philomena.Images.SearchIndex, as: ImageIndex alias Philomena.IndexWorker alias Philomena.ImageFeatures.ImageFeature alias Philomena.SourceChanges.SourceChange @@ -812,7 +812,7 @@ defmodule Philomena.Images do def user_name_reindex(old_name, new_name) do data = ImageIndex.user_name_update_by_query(old_name, new_name) - Elasticsearch.update_by_query(Image, data.query, data.set_replacements, data.replacements) + Search.update_by_query(Image, data.query, data.set_replacements, data.replacements) end def reindex_image(%Image{} = image) do @@ -845,7 +845,7 @@ defmodule Philomena.Images do Image |> preload(^indexing_preloads()) |> where([i], field(i, ^column) in ^condition) - |> Elasticsearch.reindex(Image) + |> Search.reindex(Image) end def purge_files(image, hidden_key) do diff --git a/lib/philomena/images/query.ex b/lib/philomena/images/query.ex index db00a20b..575c6e71 100644 --- a/lib/philomena/images/query.ex +++ b/lib/philomena/images/query.ex @@ -1,5 +1,5 @@ defmodule Philomena.Images.Query do - alias Philomena.Search.Parser + alias PhilomenaQuery.Parse.Parser alias Philomena.Repo defp gallery_id_transform(_ctx, value) do @@ -60,7 +60,7 @@ defmodule Philomena.Images.Query do do: {:error, "Unknown `my' value."} defp invalid_filter_guard(ctx, search_string) do - case parse(user_fields(), ctx, Philomena.Search.String.normalize(search_string)) do + case parse(user_fields(), ctx, PhilomenaQuery.Parse.String.normalize(search_string)) do {:ok, query} -> query _error -> %{match_all: %{}} end diff --git a/lib/philomena/images/elasticsearch_index.ex b/lib/philomena/images/search_index.ex similarity index 98% rename from lib/philomena/images/elasticsearch_index.ex rename to lib/philomena/images/search_index.ex index 0e5fb296..9fb29dc2 100644 --- a/lib/philomena/images/elasticsearch_index.ex +++ b/lib/philomena/images/search_index.ex @@ -1,5 +1,5 @@ -defmodule Philomena.Images.ElasticsearchIndex do - @behaviour Philomena.ElasticsearchIndex +defmodule Philomena.Images.SearchIndex do + @behaviour PhilomenaQuery.SearchIndex @impl true def index_name do diff --git a/lib/philomena/posts.ex b/lib/philomena/posts.ex index 7a7fb7a5..16795e6c 100644 --- a/lib/philomena/posts.ex +++ b/lib/philomena/posts.ex @@ -7,12 +7,12 @@ defmodule Philomena.Posts do alias Ecto.Multi alias Philomena.Repo - alias Philomena.Elasticsearch + alias PhilomenaQuery.Search alias Philomena.Topics.Topic alias Philomena.Topics alias Philomena.UserStatistics alias Philomena.Posts.Post - alias Philomena.Posts.ElasticsearchIndex, as: PostIndex + alias Philomena.Posts.SearchIndex, as: PostIndex alias Philomena.IndexWorker alias Philomena.Forums.Forum alias Philomena.Notifications @@ -309,7 +309,7 @@ defmodule Philomena.Posts do def user_name_reindex(old_name, new_name) do data = PostIndex.user_name_update_by_query(old_name, new_name) - Elasticsearch.update_by_query(Post, data.query, data.set_replacements, data.replacements) + Search.update_by_query(Post, data.query, data.set_replacements, data.replacements) end defp reindex_after_update({:ok, post}) do @@ -336,6 +336,6 @@ defmodule Philomena.Posts do Post |> preload(^indexing_preloads()) |> where([p], field(p, ^column) in ^condition) - |> Elasticsearch.reindex(Post) + |> Search.reindex(Post) end end diff --git a/lib/philomena/posts/query.ex b/lib/philomena/posts/query.ex index 463216b9..27773776 100644 --- a/lib/philomena/posts/query.ex +++ b/lib/philomena/posts/query.ex @@ -1,5 +1,5 @@ defmodule Philomena.Posts.Query do - alias Philomena.Search.Parser + alias PhilomenaQuery.Parse.Parser defp user_id_transform(_ctx, data) do case Integer.parse(data) do diff --git a/lib/philomena/posts/elasticsearch_index.ex b/lib/philomena/posts/search_index.ex similarity index 96% rename from lib/philomena/posts/elasticsearch_index.ex rename to lib/philomena/posts/search_index.ex index 43a14284..b0fdb94c 100644 --- a/lib/philomena/posts/elasticsearch_index.ex +++ b/lib/philomena/posts/search_index.ex @@ -1,5 +1,5 @@ -defmodule Philomena.Posts.ElasticsearchIndex do - @behaviour Philomena.ElasticsearchIndex +defmodule Philomena.Posts.SearchIndex do + @behaviour PhilomenaQuery.SearchIndex @impl true def index_name do diff --git a/lib/philomena/reports.ex b/lib/philomena/reports.ex index 25a04e74..1639929d 100644 --- a/lib/philomena/reports.ex +++ b/lib/philomena/reports.ex @@ -6,9 +6,9 @@ defmodule Philomena.Reports do import Ecto.Query, warn: false alias Philomena.Repo - alias Philomena.Elasticsearch + alias PhilomenaQuery.Search alias Philomena.Reports.Report - alias Philomena.Reports.ElasticsearchIndex, as: ReportIndex + alias Philomena.Reports.SearchIndex, as: ReportIndex alias Philomena.IndexWorker alias Philomena.Polymorphic @@ -152,7 +152,7 @@ defmodule Philomena.Reports do def user_name_reindex(old_name, new_name) do data = ReportIndex.user_name_update_by_query(old_name, new_name) - Elasticsearch.update_by_query(Report, data.query, data.set_replacements, data.replacements) + Search.update_by_query(Report, data.query, data.set_replacements, data.replacements) end defp reindex_after_update({:ok, report}) do @@ -183,7 +183,7 @@ defmodule Philomena.Reports do |> preload([:user, :admin]) |> Repo.all() |> Polymorphic.load_polymorphic(reportable: [reportable_id: :reportable_type]) - |> Enum.map(&Elasticsearch.index_document(&1, Report)) + |> Enum.map(&Search.index_document(&1, Report)) end def count_reports(user) do diff --git a/lib/philomena/reports/query.ex b/lib/philomena/reports/query.ex index c085a604..d5adc2cc 100644 --- a/lib/philomena/reports/query.ex +++ b/lib/philomena/reports/query.ex @@ -1,5 +1,5 @@ defmodule Philomena.Reports.Query do - alias Philomena.Search.Parser + alias PhilomenaQuery.Parse.Parser defp fields do [ diff --git a/lib/philomena/reports/elasticsearch_index.ex b/lib/philomena/reports/search_index.ex similarity index 96% rename from lib/philomena/reports/elasticsearch_index.ex rename to lib/philomena/reports/search_index.ex index bafcf673..15a08708 100644 --- a/lib/philomena/reports/elasticsearch_index.ex +++ b/lib/philomena/reports/search_index.ex @@ -1,5 +1,5 @@ -defmodule Philomena.Reports.ElasticsearchIndex do - @behaviour Philomena.ElasticsearchIndex +defmodule Philomena.Reports.SearchIndex do + @behaviour PhilomenaQuery.SearchIndex @impl true def index_name do diff --git a/lib/philomena/schema/search.ex b/lib/philomena/schema/search.ex index 47887b75..9b4e7e08 100644 --- a/lib/philomena/schema/search.ex +++ b/lib/philomena/schema/search.ex @@ -1,6 +1,6 @@ defmodule Philomena.Schema.Search do alias Philomena.Images.Query - alias Philomena.Search.String + alias PhilomenaQuery.Parse.String import Ecto.Changeset def validate_search(changeset, field, user, watched \\ false) do diff --git a/lib/philomena/schema/time.ex b/lib/philomena/schema/time.ex index af36538a..fff11419 100644 --- a/lib/philomena/schema/time.ex +++ b/lib/philomena/schema/time.ex @@ -1,5 +1,5 @@ defmodule Philomena.Schema.Time do - alias Philomena.RelativeDate + alias PhilomenaQuery.RelativeDate import Ecto.Changeset def assign_time(changeset, field, target_field) do diff --git a/lib/philomena/search/string.ex b/lib/philomena/search/string.ex deleted file mode 100644 index a7f1441c..00000000 --- a/lib/philomena/search/string.ex +++ /dev/null @@ -1,13 +0,0 @@ -defmodule Philomena.Search.String do - def normalize(nil) do - "" - end - - def normalize(str) do - str - |> String.replace("\r", "") - |> String.split("\n", trim: true) - |> Enum.map(fn s -> "(#{s})" end) - |> Enum.join(" || ") - end -end diff --git a/lib/philomena/tags.ex b/lib/philomena/tags.ex index d4d938b7..1f6e80c6 100644 --- a/lib/philomena/tags.ex +++ b/lib/philomena/tags.ex @@ -6,7 +6,7 @@ defmodule Philomena.Tags do import Ecto.Query, warn: false alias Philomena.Repo - alias Philomena.Elasticsearch + alias PhilomenaQuery.Search alias Philomena.IndexWorker alias Philomena.TagAliasWorker alias Philomena.TagUnaliasWorker @@ -194,12 +194,12 @@ defmodule Philomena.Tags do {:ok, tag} = Repo.delete(tag) - Elasticsearch.delete_document(tag.id, Tag) + Search.delete_document(tag.id, Tag) Image |> where([i], i.id in ^image_ids) |> preload(^Images.indexing_preloads()) - |> Elasticsearch.reindex(Image) + |> Search.reindex(Image) end def alias_tag(%Tag{} = tag, attrs) do @@ -301,13 +301,13 @@ defmodule Philomena.Tags do |> join(:inner, [i], _ in assoc(i, :tags)) |> where([_i, t], t.id == ^tag.id) |> preload(^Images.indexing_preloads()) - |> Elasticsearch.reindex(Image) + |> Search.reindex(Image) Filter |> where([f], fragment("? @> ARRAY[?]::integer[]", f.hidden_tag_ids, ^tag.id)) |> or_where([f], fragment("? @> ARRAY[?]::integer[]", f.spoilered_tag_ids, ^tag.id)) |> preload(^Filters.indexing_preloads()) - |> Elasticsearch.reindex(Filter) + |> Search.reindex(Filter) end def unalias_tag(%Tag{} = tag) do @@ -416,7 +416,7 @@ defmodule Philomena.Tags do Tag |> preload(^indexing_preloads()) |> where([t], field(t, ^column) in ^condition) - |> Elasticsearch.reindex(Tag) + |> Search.reindex(Tag) end alias Philomena.Tags.Implication diff --git a/lib/philomena/tags/query.ex b/lib/philomena/tags/query.ex index fd905775..5bfd2126 100644 --- a/lib/philomena/tags/query.ex +++ b/lib/philomena/tags/query.ex @@ -1,5 +1,5 @@ defmodule Philomena.Tags.Query do - alias Philomena.Search.Parser + alias PhilomenaQuery.Parse.Parser defp fields do [ diff --git a/lib/philomena/tags/elasticsearch_index.ex b/lib/philomena/tags/search_index.ex similarity index 95% rename from lib/philomena/tags/elasticsearch_index.ex rename to lib/philomena/tags/search_index.ex index 86a7e11e..be592d36 100644 --- a/lib/philomena/tags/elasticsearch_index.ex +++ b/lib/philomena/tags/search_index.ex @@ -1,5 +1,5 @@ -defmodule Philomena.Tags.ElasticsearchIndex do - @behaviour Philomena.ElasticsearchIndex +defmodule Philomena.Tags.SearchIndex do + @behaviour PhilomenaQuery.SearchIndex @impl true def index_name do diff --git a/lib/philomena/user_downvote_wipe.ex b/lib/philomena/user_downvote_wipe.ex index dd796c44..6fb217fe 100644 --- a/lib/philomena/user_downvote_wipe.ex +++ b/lib/philomena/user_downvote_wipe.ex @@ -1,6 +1,6 @@ defmodule Philomena.UserDownvoteWipe do - alias Philomena.Batch - alias Philomena.Elasticsearch + alias PhilomenaQuery.Batch + alias PhilomenaQuery.Search alias Philomena.Users alias Philomena.Users.User alias Philomena.Images.Image @@ -63,7 +63,7 @@ defmodule Philomena.UserDownvoteWipe do Image |> where([i], i.id in ^image_ids) |> preload(^Images.indexing_preloads()) - |> Elasticsearch.reindex(Image) + |> Search.reindex(Image) # allow time for indexing to catch up :timer.sleep(:timer.seconds(10)) diff --git a/lib/philomena/workers/index_worker.ex b/lib/philomena/workers/index_worker.ex index 3544d122..91ceaa3f 100644 --- a/lib/philomena/workers/index_worker.ex +++ b/lib/philomena/workers/index_worker.ex @@ -15,7 +15,7 @@ defmodule Philomena.IndexWorker do # Image # |> preload(^indexing_preloads()) # |> where([i], field(i, ^column) in ^condition) - # |> Elasticsearch.reindex(Image) + # |> Search.reindex(Image) # end # def perform(module, column, condition) do diff --git a/lib/philomena/workers/tag_change_revert_worker.ex b/lib/philomena/workers/tag_change_revert_worker.ex index 774bfd6a..519b8404 100644 --- a/lib/philomena/workers/tag_change_revert_worker.ex +++ b/lib/philomena/workers/tag_change_revert_worker.ex @@ -1,7 +1,7 @@ defmodule Philomena.TagChangeRevertWorker do alias Philomena.TagChanges.TagChange alias Philomena.TagChanges - alias Philomena.Batch + alias PhilomenaQuery.Batch alias Philomena.Repo import Ecto.Query diff --git a/lib/philomena_query/batch.ex b/lib/philomena_query/batch.ex new file mode 100644 index 00000000..ce78cb6a --- /dev/null +++ b/lib/philomena_query/batch.ex @@ -0,0 +1,111 @@ +defmodule PhilomenaQuery.Batch do + @moduledoc """ + Locking-reduced database batch operations. + + These operations are non-transactional by their very nature. This prevents inadvertent + downtimes due to blocking, but can result in consistency errors in the database, + and so should be used sparingly. + + They are best suited for when large numbers of rows can be expected to be processed, + as doing so may otherwise result in Ecto timing out the query. + """ + + alias Philomena.Repo + import Ecto.Query + + @type queryable :: any() + + @type batch_size :: {:batch_size, integer()} + @type id_field :: {:id_field, atom()} + @type batch_options :: [batch_size() | id_field()] + + @type record_batch_callback :: ([struct()] -> any()) + @type query_batch_callback :: ([Ecto.Query.t()] -> any()) + + @doc """ + Execute a callback with lists of schema structures on a queryable, + using batches to avoid locking. + + Valid options: + * `batch_size` (integer) - the number of records to load per batch + * `id_field` (atom) - the name of the field containing the ID + + ## Example + + queryable = from i in Image, where: i.image_width >= 1920 + + cb = fn images -> + Enum.each(images, &IO.inspect(&1.id)) + end + + PhilomenaQuery.Batch.record_batches(queryable, cb) + + """ + @spec record_batches(queryable(), batch_options(), record_batch_callback()) :: [] + def record_batches(queryable, opts \\ [], callback) do + query_batches(queryable, opts, &callback.(Repo.all(&1))) + end + + @doc """ + Execute a callback with bulk queries on a queryable, using batches to avoid locking. + + Valid options: + * `batch_size` (integer) - the number of records to load per batch + * `id_field` (atom) - the name of the field containing the ID + + > #### Info {: .info} + > + > If you are looking to receive schema structures (e.g., you are querying for `Image`s, + > and you want to receive `Image` objects, then use `record_batches/3` instead. + + An `m:Ecto.Query` which selects all IDs in the current batch is passed into the callback + during each invocation. + + ## Example + + queryable = from ui in ImageVote, where: ui.user_id == 1234 + + opts = [id_field: :image_id] + + cb = fn bulk_query -> + Repo.delete_all(bulk_query) + end + + PhilomenaQuery.Batch.query_batches(queryable, opts, cb) + + """ + @spec query_batches(queryable(), batch_options(), query_batch_callback()) :: [] + def query_batches(queryable, opts \\ [], callback) do + ids = load_ids(queryable, -1, opts) + + query_batches(queryable, opts, callback, ids) + end + + defp query_batches(_queryable, _opts, _callback, []), do: [] + + defp query_batches(queryable, opts, callback, ids) do + id_field = Keyword.get(opts, :id_field, :id) + + queryable + |> where([m], field(m, ^id_field) in ^ids) + |> callback.() + + ids = load_ids(queryable, Enum.max(ids), opts) + + query_batches(queryable, opts, callback, ids) + end + + defp load_ids(queryable, max_id, opts) do + id_field = Keyword.get(opts, :id_field, :id) + batch_size = Keyword.get(opts, :batch_size, 1000) + + queryable + |> exclude(:preload) + |> exclude(:order_by) + |> order_by(asc: ^id_field) + |> where([m], field(m, ^id_field) > ^max_id) + |> select([m], field(m, ^id_field)) + |> limit(^batch_size) + |> Repo.all() + end +end diff --git a/lib/philomena/search/bool_parser.ex b/lib/philomena_query/parse/bool_parser.ex similarity index 84% rename from lib/philomena/search/bool_parser.ex rename to lib/philomena_query/parse/bool_parser.ex index bb389096..c897f7e3 100644 --- a/lib/philomena/search/bool_parser.ex +++ b/lib/philomena_query/parse/bool_parser.ex @@ -1,4 +1,6 @@ -defmodule Philomena.Search.BoolParser do +defmodule PhilomenaQuery.Parse.BoolParser do + @moduledoc false + import NimbleParsec space = diff --git a/lib/philomena/search/date_parser.ex b/lib/philomena_query/parse/date_parser.ex similarity index 96% rename from lib/philomena/search/date_parser.ex rename to lib/philomena_query/parse/date_parser.ex index 5c8a8cb1..db590af0 100644 --- a/lib/philomena/search/date_parser.ex +++ b/lib/philomena_query/parse/date_parser.ex @@ -1,4 +1,6 @@ -defmodule Philomena.Search.DateParser do +defmodule PhilomenaQuery.Parse.DateParser do + @moduledoc false + import NimbleParsec @dialyzer [:no_match, :no_unused] @@ -100,9 +102,9 @@ defmodule Philomena.Search.DateParser do end defp relative_datetime(_rest, [count, scale], context, _line, _offset) do - millenium_seconds = 31_536_000_000 + millennium_seconds = 31_536_000_000 - case count * scale <= millenium_seconds do + case count * scale <= millennium_seconds do true -> now = DateTime.utc_now() @@ -113,7 +115,7 @@ defmodule Philomena.Search.DateParser do _false -> {:error, - "invalid date format in input; requested time #{count * scale} seconds is over a millenium ago"} + "invalid date format in input; requested time #{count * scale} seconds is over a millennium ago"} end end diff --git a/lib/philomena/search/evaluator.ex b/lib/philomena_query/parse/evaluator.ex similarity index 90% rename from lib/philomena/search/evaluator.ex rename to lib/philomena_query/parse/evaluator.ex index 25ef2337..6cb6d6cc 100644 --- a/lib/philomena/search/evaluator.ex +++ b/lib/philomena_query/parse/evaluator.ex @@ -1,6 +1,25 @@ -defmodule Philomena.Search.Evaluator do +defmodule PhilomenaQuery.Parse.Evaluator do + @moduledoc """ + Tools to evaluate whether a search query matches a document. + """ + # TODO: rethink the necessity of this module. - # Can we do this in elasticsearch instead? + # Can we do this in the search engine instead? + + @doc """ + Check whether a hit is matched by a query. + + - `doc` - a document definition. This could be returned by the index's `as_json/1` function. + - `query` - a search query + + ## Example + + iex> Evaluator.hits?(def, %{term: %{tags: "safe"}}) + true + + """ + @spec hits?(map(), map()) :: boolean() + def hits?(doc, query) def hits?(doc, %{bool: bool_query}) do must(doc, bool_query[:must]) and @@ -101,7 +120,7 @@ defmodule Philomena.Search.Evaluator do defp atomify(atom) when is_atom(atom), do: atom defp atomify(string) when is_binary(string), do: String.to_existing_atom(string) - def levenshtein(s1, s2) do + defp levenshtein(s1, s2) do {dist, _lookup} = levenshtein_lookup(s1, s2, %{}, 0) dist diff --git a/lib/philomena/search/float_parser.ex b/lib/philomena_query/parse/float_parser.ex similarity index 81% rename from lib/philomena/search/float_parser.ex rename to lib/philomena_query/parse/float_parser.ex index 8b5321e2..2fa253fc 100644 --- a/lib/philomena/search/float_parser.ex +++ b/lib/philomena_query/parse/float_parser.ex @@ -1,8 +1,10 @@ -defmodule Philomena.Search.FloatParser do +defmodule PhilomenaQuery.Parse.FloatParser do + @moduledoc false + import NimbleParsec - defp to_number(input), do: Philomena.Search.Helpers.to_number(input) - defp range(input), do: Philomena.Search.Helpers.range(input) + defp to_number(input), do: PhilomenaQuery.Parse.Helpers.to_number(input) + defp range(input), do: PhilomenaQuery.Parse.Helpers.range(input) space = choice([string(" "), string("\t"), string("\n"), string("\r"), string("\v"), string("\f")]) diff --git a/lib/philomena/search/helpers.ex b/lib/philomena_query/parse/helpers.ex similarity index 90% rename from lib/philomena/search/helpers.ex rename to lib/philomena_query/parse/helpers.ex index 33a8597b..eb1e72b9 100644 --- a/lib/philomena/search/helpers.ex +++ b/lib/philomena_query/parse/helpers.ex @@ -1,4 +1,6 @@ -defmodule Philomena.Search.Helpers do +defmodule PhilomenaQuery.Parse.Helpers do + @moduledoc false + # Apparently, it's too hard for the standard library to to parse a number # as a float if it doesn't contain a decimal point. WTF def to_number(term) do diff --git a/lib/philomena/search/int_parser.ex b/lib/philomena_query/parse/int_parser.ex similarity index 75% rename from lib/philomena/search/int_parser.ex rename to lib/philomena_query/parse/int_parser.ex index d6e4f509..a3f7842a 100644 --- a/lib/philomena/search/int_parser.ex +++ b/lib/philomena_query/parse/int_parser.ex @@ -1,8 +1,10 @@ -defmodule Philomena.Search.IntParser do +defmodule PhilomenaQuery.Parse.IntParser do + @moduledoc false + import NimbleParsec - defp to_int(input), do: Philomena.Search.Helpers.to_int(input) - defp range(input), do: Philomena.Search.Helpers.range(input) + defp to_int(input), do: PhilomenaQuery.Parse.Helpers.to_int(input) + defp range(input), do: PhilomenaQuery.Parse.Helpers.range(input) space = choice([string(" "), string("\t"), string("\n"), string("\r"), string("\v"), string("\f")]) diff --git a/lib/philomena/search/ip_parser.ex b/lib/philomena_query/parse/ip_parser.ex similarity index 98% rename from lib/philomena/search/ip_parser.ex rename to lib/philomena_query/parse/ip_parser.ex index c7476a0b..28472407 100644 --- a/lib/philomena/search/ip_parser.ex +++ b/lib/philomena_query/parse/ip_parser.ex @@ -1,4 +1,6 @@ -defmodule Philomena.Search.IpParser do +defmodule PhilomenaQuery.Parse.IpParser do + @moduledoc false + import NimbleParsec ipv4_octet = diff --git a/lib/philomena/search/lexer.ex b/lib/philomena_query/parse/lexer.ex similarity index 94% rename from lib/philomena/search/lexer.ex rename to lib/philomena_query/parse/lexer.ex index 9096ee0e..648099a4 100644 --- a/lib/philomena/search/lexer.ex +++ b/lib/philomena_query/parse/lexer.ex @@ -1,7 +1,9 @@ -defmodule Philomena.Search.Lexer do +defmodule PhilomenaQuery.Parse.Lexer do + @moduledoc false + import NimbleParsec - defp to_number(input), do: Philomena.Search.Helpers.to_number(input) + defp to_number(input), do: PhilomenaQuery.Parse.Helpers.to_number(input) space = choice([string(" "), string("\t"), string("\n"), string("\r"), string("\v"), string("\f")]) diff --git a/lib/philomena/search/literal_parser.ex b/lib/philomena_query/parse/literal_parser.ex similarity index 89% rename from lib/philomena/search/literal_parser.ex rename to lib/philomena_query/parse/literal_parser.ex index 59224960..253d647f 100644 --- a/lib/philomena/search/literal_parser.ex +++ b/lib/philomena_query/parse/literal_parser.ex @@ -1,8 +1,10 @@ -defmodule Philomena.Search.LiteralParser do +defmodule PhilomenaQuery.Parse.LiteralParser do + @moduledoc false + import NimbleParsec @dialyzer [:no_match, :no_unused] - defp to_number(input), do: Philomena.Search.Helpers.to_number(input) + defp to_number(input), do: PhilomenaQuery.Parse.Helpers.to_number(input) float = ascii_string([?0..?9], min: 1) diff --git a/lib/philomena/search/ngram_parser.ex b/lib/philomena_query/parse/ngram_parser.ex similarity index 51% rename from lib/philomena/search/ngram_parser.ex rename to lib/philomena_query/parse/ngram_parser.ex index dd8d41ca..7f2060e2 100644 --- a/lib/philomena/search/ngram_parser.ex +++ b/lib/philomena_query/parse/ngram_parser.ex @@ -1,5 +1,7 @@ -defmodule Philomena.Search.NgramParser do - alias Philomena.Search.LiteralParser +defmodule PhilomenaQuery.Parse.NgramParser do + @moduledoc false + + alias PhilomenaQuery.Parse.LiteralParser # Dummy stub. Used for convenient parser implementation. def parse(input), do: LiteralParser.parse(input) diff --git a/lib/philomena/search/parser.ex b/lib/philomena_query/parse/parser.ex similarity index 73% rename from lib/philomena/search/parser.ex rename to lib/philomena_query/parse/parser.ex index b2f5e47e..ba4b0597 100644 --- a/lib/philomena/search/parser.ex +++ b/lib/philomena_query/parse/parser.ex @@ -1,5 +1,34 @@ -defmodule Philomena.Search.Parser do - alias Philomena.Search.{ +defmodule PhilomenaQuery.Parse.Parser do + @moduledoc """ + A search language for safely evaluating user-input queries. + + The query language supports the following features: + - Disjunction (OR/||) + - Conjunction (AND/&&/,) + - Negation (NOT/-/!) + - Expression boosting + - Parenthetical grouping + + Several types of terms are supported: + - Booleans + - Dates (absolute and relative, time points and ranges) + - Floats + - Integers + - IP Addresses + - Literal text + - Stemmed text + + Specific terms can support the following features: + - Range queries (.lte/.lt/.gte/.gt) + - Fuzzing (~0.5) + - Wildcarding (*?) + - CIDR masks (/27) + + The rich search expression grammar is arguably a defining feature of Philomena, and its + feature set makes it stand out in comparison to traditional boorus. + """ + + alias PhilomenaQuery.Parse.{ BoolParser, DateParser, FloatParser, @@ -12,6 +41,31 @@ defmodule Philomena.Search.Parser do TermRangeParser } + @type context :: any() + @type query :: map() + + @type default_field_type :: :term | :ngram + + @type transform_result :: {:ok, query()} | {:error, String.t()} + @type transform :: (context, String.t() -> transform_result()) + + @type t :: %__MODULE__{ + default_field: {String.t(), default_field_type()}, + bool_fields: [String.t()], + date_fields: [String.t()], + float_fields: [String.t()], + int_fields: [String.t()], + ip_fields: [String.t()], + literal_fields: [String.t()], + ngram_fields: [String.t()], + custom_fields: [String.t()], + transforms: %{String.t() => transform()}, + aliases: %{String.t() => String.t()}, + no_downcase_fields: [String.t()], + __fields__: map(), + __data__: context() + } + defstruct [ :default_field, bool_fields: [], @@ -31,6 +85,37 @@ defmodule Philomena.Search.Parser do @max_clause_count 512 + @doc """ + Creates a `Parser` suitable for safely parsing user-input queries. + + Fields refer to attributes of the indexed document which will be searchable with + `m:PhilomenaQuery.Search`. + + Available options: + - `bool_fields` - a list of field names parsed as booleans + - `float_fields` - a list of field names parsed as floats + - `int_fields` - a list of field names parsed as integers + - `ip_fields` - a list of field names parsed as IP CIDR masks + - `literal_fields` - wildcardable fields which are searched as the exact value + - `ngram_fields` - wildcardable fields which are searched as stemmed values + - `custom_fields` - fields which do not exist on the document and are created by a callback + - `transforms` - a map of custom field names to transform functions + - `aliases` - a map of field names to the names they should have in the search engine + - `no_downcase_fields` - a list of field names which do not have string downcasing applied + + ## Example + + options = [ + bool_fields: ["hidden"], + custom_fields: ["example"], + transforms: %{"example" => fn _ctx, term -> %{term: %{term => "example"}} end}, + aliases: %{"hidden" => "hidden_from_users"} + ] + + Parser.parser(options) + + """ + @spec parser(keyword()) :: t() def parser(options) do parser = struct(Parser, options) @@ -47,6 +132,34 @@ defmodule Philomena.Search.Parser do %{parser | __fields__: Map.new(fields)} end + @doc """ + Parse the query into a definition suitable for the search engine. + + The parser argument should have been created with a previous call to `parser/1`. When the + `context` argument is passed, it becomes the first argument to any transform functions defined + in the `transform` option. + + ## Example + + iex> Parser.parse(parser, "safe") + {:ok, %{term: %{"namespaced_tags.name" => "safe"}}} + + iex> Parser.parse(nil, "safe OR solo") + {:ok, + %{ + bool: %{ + should: [ + %{term: %{"namespaced_tags.name" => "safe"}}, + %{term: %{"namespaced_tags.name" => "solo"}} + ] + } + }} + + iex> Parser.parse(parser, ")") + {:error, "Imbalanced parentheses."} + + """ + @spec parse(t(), String.t(), context()) :: {:ok, query()} | {:error, String.t()} def parse(parser, input, context \\ nil) # Empty search should emit a match_none. diff --git a/lib/philomena_query/parse/string.ex b/lib/philomena_query/parse/string.ex new file mode 100644 index 00000000..f6dc2fa0 --- /dev/null +++ b/lib/philomena_query/parse/string.ex @@ -0,0 +1,32 @@ +defmodule PhilomenaQuery.Parse.String do + @moduledoc """ + Search string normalization utilities. + """ + + @doc """ + Convert a multiline or empty search string into a single search string. + + ## Examples + + iex> Search.String.normalize(nil) + "" + + iex> Search.String.normalize("foo\nbar") + "(foo) || (bar)" + + """ + @spec normalize(String.t() | nil) :: String.t() + def normalize(str) + + def normalize(nil) do + "" + end + + def normalize(str) do + str + |> String.replace("\r", "") + |> String.split("\n", trim: true) + |> Enum.map(fn s -> "(#{s})" end) + |> Enum.join(" || ") + end +end diff --git a/lib/philomena/search/term_range_parser.ex b/lib/philomena_query/parse/term_range_parser.ex similarity index 90% rename from lib/philomena/search/term_range_parser.ex rename to lib/philomena_query/parse/term_range_parser.ex index e956aed5..f5613da4 100644 --- a/lib/philomena/search/term_range_parser.ex +++ b/lib/philomena_query/parse/term_range_parser.ex @@ -1,6 +1,8 @@ -defmodule Philomena.Search.TermRangeParser do - alias Philomena.Search.LiteralParser - alias Philomena.Search.NgramParser +defmodule PhilomenaQuery.Parse.TermRangeParser do + @moduledoc false + + alias PhilomenaQuery.Parse.LiteralParser + alias PhilomenaQuery.Parse.NgramParser # Unfortunately, we can't use NimbleParsec here. It requires # the compiler, and we're not in a macro environment. diff --git a/lib/philomena/relative_date.ex b/lib/philomena_query/relative_date.ex similarity index 63% rename from lib/philomena/relative_date.ex rename to lib/philomena_query/relative_date.ex index 1c678d15..35b0fc82 100644 --- a/lib/philomena/relative_date.ex +++ b/lib/philomena_query/relative_date.ex @@ -1,4 +1,8 @@ -defmodule Philomena.RelativeDate do +defmodule PhilomenaQuery.RelativeDate do + @moduledoc """ + Relative date parsing, for strings like "a week ago" or "5 years from now". + """ + import NimbleParsec number_words = @@ -72,6 +76,13 @@ defmodule Philomena.RelativeDate do defparsecp(:relative_date, relative_date) + @doc """ + Parse an absolute date in valid ISO 8601 format, or an English-language relative date. + + See `parse_absolute/1` and `parse_relative/1` for examples of what may be accepted + by this function. + """ + @spec parse_absolute(String.t()) :: {:ok, DateTime.t()} | {:error, any()} def parse(input) do input = input @@ -87,6 +98,22 @@ defmodule Philomena.RelativeDate do end end + @doc """ + Parse an absolute date, given in a valid ISO 8601 format. + + ## Example + + iex> PhilomenaQuery.RelativeDate.parse_absolute("2024-01-01T00:00:00Z") + {:ok, ~U[2024-01-01 00:00:00Z]} + + iex> PhilomenaQuery.RelativeDate.parse_absolute("2024-01-01T00:00:00-01:00") + {:ok, ~U[2024-01-01 01:00:00Z] + + iex> PhilomenaQuery.RelativeDate.parse_absolute("2024") + {:error, "Parse error"} + + """ + @spec parse_absolute(String.t()) :: {:ok, DateTime.t()} | {:error, any()} def parse_absolute(input) do case DateTime.from_iso8601(input) do {:ok, datetime, _offset} -> @@ -97,6 +124,25 @@ defmodule Philomena.RelativeDate do end end + @doc """ + Parse an English-language relative date. Accepts "moon" to mean 1000 years from now. + + ## Example + + iex> PhilomenaQuery.RelativeDate.parse_relative("a year ago") + {:ok, ~U[2023-01-01 00:00:00Z] + + iex> PhilomenaQuery.RelativeDate.parse_relative("three days from now") + {:ok, ~U[2024-01-04 00:00:00Z]} + + iex> PhilomenaQuery.RelativeDate.parse_relative("moon") + {:ok, ~U[3024-01-01 00:00:00Z]} + + iex> PhilomenaQuery.RelativeDate.parse_relative("2024") + {:error, "Parse error"} + + """ + @spec parse_relative(String.t()) :: {:ok, DateTime.t()} | {:error, any()} def parse_relative(input) do case relative_date(input) do {:ok, [moon: _moon], _1, _2, _3, _4} -> diff --git a/lib/philomena_query/search.ex b/lib/philomena_query/search.ex new file mode 100644 index 00000000..13a34f44 --- /dev/null +++ b/lib/philomena_query/search.ex @@ -0,0 +1,654 @@ +defmodule PhilomenaQuery.Search do + @moduledoc """ + Low-level search engine interaction. + + This module generates and delivers search bodies to the OpenSearch backend. + + Note that before an index can be used to index or query documents, a call to + `create_index!/1` must be made. When setting up an application, or dealing with data loss + in the search engine, you must call `create_index!/1` before running an indexing task. + """ + + alias PhilomenaQuery.Batch + alias Philomena.Repo + require Logger + import Ecto.Query + import Elastix.HTTP + + alias Philomena.Comments.Comment + alias Philomena.Galleries.Gallery + alias Philomena.Images.Image + alias Philomena.Posts.Post + alias Philomena.Reports.Report + alias Philomena.Tags.Tag + alias Philomena.Filters.Filter + + alias Philomena.Comments.SearchIndex, as: CommentIndex + alias Philomena.Galleries.SearchIndex, as: GalleryIndex + alias Philomena.Images.SearchIndex, as: ImageIndex + alias Philomena.Posts.SearchIndex, as: PostIndex + alias Philomena.Reports.SearchIndex, as: ReportIndex + alias Philomena.Tags.SearchIndex, as: TagIndex + alias Philomena.Filters.SearchIndex, as: FilterIndex + + defp index_for(Comment), do: CommentIndex + defp index_for(Gallery), do: GalleryIndex + defp index_for(Image), do: ImageIndex + defp index_for(Post), do: PostIndex + defp index_for(Report), do: ReportIndex + defp index_for(Tag), do: TagIndex + defp index_for(Filter), do: FilterIndex + + defp opensearch_url do + Application.get_env(:philomena, :opensearch_url) + end + + @type index_module :: module() + @type queryable :: any() + @type query_body :: map() + + @type replacement :: %{ + path: [String.t()], + old: term(), + new: term() + } + + @type search_definition :: %{ + module: index_module(), + body: query_body(), + page_number: integer(), + page_size: integer() + } + + @type pagination_params :: %{ + optional(:page_number) => integer(), + optional(:page_size) => integer() + } + + @doc ~S""" + Create the index with the module's index name and mapping. + + `PUT /#{index_name}` + + You **must** use this function before indexing documents in order for the mapping to be created + correctly. If you index documents without a mapping created, the search engine will create a + mapping which does not contain the correct types for mapping fields, which will require + destroying and recreating the index. + + ## Example + + iex> Search.create_index!(Image) + + """ + @spec create_index!(index_module()) :: any() + def create_index!(module) do + index = index_for(module) + + Elastix.Index.create( + opensearch_url(), + index.index_name(), + index.mapping() + ) + end + + @doc ~S""" + Delete the index with the module's index name. + + `DELETE /#{index_name}` + + This undoes the effect of `create_index!/1` and removes the index permanently, deleting + all indexed documents within. + + ## Example + + iex> Search.delete_index!(Image) + + """ + @spec delete_index!(index_module()) :: any() + def delete_index!(module) do + index = index_for(module) + + Elastix.Index.delete(opensearch_url(), index.index_name()) + end + + @doc ~S""" + Update the schema mapping for the module's index name. + + `PUT /#{index_name}/_mapping` + + This is used to add new fields to an existing search mapping. This cannot be used to + remove fields; removing fields requires recreating the index. + + ## Example + + iex> Search.update_mapping!(Image) + + """ + @spec update_mapping!(index_module()) :: any() + def update_mapping!(module) do + index = index_for(module) + + index_name = index.index_name() + mapping = index.mapping().mappings.properties + + Elastix.Mapping.put(opensearch_url(), index_name, "_doc", %{properties: mapping}, + include_type_name: true + ) + end + + @doc ~S""" + Add a single document to the index named by the module. + + `PUT /#{index_name}/_doc/#{id}` + + This allows the search engine to query the document. + + Note that indexing is near real-time and requires an index refresh before the document will + become visible. Unless changed in the mapping, this happens after 5 seconds have elapsed. + + ## Example + + iex> Search.index_document(%Image{...}, Image) + + """ + @spec index_document(struct(), index_module()) :: any() + def index_document(doc, module) do + index = index_for(module) + data = index.as_json(doc) + + Elastix.Document.index( + opensearch_url(), + index.index_name(), + "_doc", + data.id, + data + ) + end + + @doc ~S""" + Remove a single document from the index named by the module. + + `DELETE /#{index_name}/_doc/#{id}` + + This undoes the effect of `index_document/2`; it instructs the search engine to discard + the document and no longer return it in queries. + + Note that indexing is near real-time and requires an index refresh before the document will + be removed. Unless changed in the mapping, this happens after 5 seconds have elapsed. + + ## Example + + iex> Search.delete_document(image.id, Image) + + """ + @spec delete_document(term(), index_module()) :: any() + def delete_document(id, module) do + index = index_for(module) + + Elastix.Document.delete( + opensearch_url(), + index.index_name(), + "_doc", + id + ) + end + + @doc """ + Efficiently index a batch of documents in the index named by the module. + + This function is substantially more efficient than running `index_document/2` for + each instance of a schema struct and can index with hundreds of times the throughput. + + The queryable should be a schema type with its indexing preloads included in + the query. The options are forwarded to `PhilomenaQuery.Batch.record_batches/3`. + + Note that indexing is near real-time and requires an index refresh before documents will + become visible. Unless changed in the mapping, this happens after 5 seconds have elapsed. + + ## Example + + query = + from i in Image, + where: i.id < 100_000, + preload: ^Images.indexing_preloads() + + Search.reindex(query, Image, batch_size: 5000) + + """ + @spec reindex(queryable(), index_module(), Batch.batch_options()) :: [] + def reindex(queryable, module, opts \\ []) do + index = index_for(module) + + Batch.record_batches(queryable, opts, fn records -> + lines = + Enum.flat_map(records, fn record -> + doc = index.as_json(record) + + [ + %{index: %{_index: index.index_name(), _id: doc.id}}, + doc + ] + end) + + Elastix.Bulk.post( + opensearch_url(), + lines, + index: index.index_name(), + httpoison_options: [timeout: 30_000] + ) + end) + end + + @doc ~S""" + Asynchronously update all documents in the given index matching a query. + + `POST /#{index_name}/_update_by_query` + + This is used to replace values in documents on the fly without requiring a more-expensive + reindex operation from the database. + + `set_replacements` are used to rename values in fields which are conceptually sets (arrays). + `replacements` are used to rename values in fields which are standalone terms. + + Both `replacements` and `set_replacements` may be specified. Specifying neither will waste + the search engine's time evaluating the query and indexing the documents, so be sure to + specify at least one. + + This function does not wait for completion of the update. + + ## Examples + + query_body = %{term: %{"namespaced_tags.name" => old_name}} + replacement = %{path: ["namespaced_tags", "name"], old: old_name, new: new_name} + Search.update_by_query(Image, query_body, [], [replacement]) + + query_body = %{term: %{author: old_name}} + set_replacement = %{path: ["author"], old: old_name, new: new_name} + Search.update_by_query(Post, query_body, [set_replacement], []) + + """ + @spec update_by_query(index_module(), query_body(), [replacement()], [replacement()]) :: any() + def update_by_query(module, query_body, set_replacements, replacements) do + index = index_for(module) + + url = + opensearch_url() + |> prepare_url([index.index_name(), "_update_by_query"]) + |> append_query_string(%{conflicts: "proceed", wait_for_completion: "false"}) + + # "Painless" scripting language + script = """ + // Replace values in "sets" (arrays in the source document) + for (int i = 0; i < params.set_replacements.length; ++i) { + def replacement = params.set_replacements[i]; + def path = replacement.path; + def old_value = replacement.old; + def new_value = replacement.new; + def reference = ctx._source; + + for (int j = 0; j < path.length; ++j) { + reference = reference[path[j]]; + } + + for (int j = 0; j < reference.length; ++j) { + if (reference[j].equals(old_value)) { + reference[j] = new_value; + } + } + } + + // Replace values in standalone fields + for (int i = 0; i < params.replacements.length; ++i) { + def replacement = params.replacements[i]; + def path = replacement.path; + def old_value = replacement.old; + def new_value = replacement.new; + def reference = ctx._source; + + // A little bit more complicated: go up to the last one before it + // so that the value can actually be replaced + + for (int j = 0; j < path.length - 1; ++j) { + reference = reference[path[j]]; + } + + if (reference[path[path.length - 1]] != null && reference[path[path.length - 1]].equals(old_value)) { + reference[path[path.length - 1]] = new_value; + } + } + """ + + body = + Jason.encode!(%{ + script: %{ + source: script, + params: %{ + set_replacements: set_replacements, + replacements: replacements + } + }, + query: query_body + }) + + {:ok, %{status_code: 200}} = Elastix.HTTP.post(url, body) + end + + @doc ~S""" + Search the index named by the module. + + `GET /#{index_name}/_search` + + Given a query body, this returns the raw query results. + + ## Example + + iex> Search.search(Image, %{query: %{match_all: %{}}}) + %{ + "_shards" => %{"failed" => 0, "skipped" => 0, "successful" => 5, "total" => 5}, + "hits" => %{ + "hits" => [%{"_id" => "1", "_index" => "images", "_score" => 1.0, ...}, ...] + "max_score" => 1.0, + "total" => %{"relation" => "eq", "value" => 6} + }, + "timed_out" => false, + "took" => 1 + } + + """ + @spec search(index_module(), query_body()) :: map() + def search(module, query_body) do + index = index_for(module) + + {:ok, %{body: results, status_code: 200}} = + Elastix.Search.search( + opensearch_url(), + index.index_name(), + [], + query_body + ) + + results + end + + @doc ~S""" + Given maps of module and body, searches each index with the respective body. + + `GET /_all/_search` + + This is more efficient than performing a `search/1` for each index individually. + Like `search/1`, this returns the raw query results. + + ## Example + + iex> Search.msearch([ + ...> %{module: Image, body: %{query: %{match_all: %{}}}}, + ...> %{module: Post, body: %{query: %{match_all: %{}}}} + ...> ]) + [ + %{"_shards" => ..., "hits" => ..., "timed_out" => false, "took" => 1}, + %{"_shards" => ..., "hits" => ..., "timed_out" => false, "took" => 2} + ] + + """ + @spec msearch([search_definition()]) :: [map()] + def msearch(definitions) do + msearch_body = + Enum.flat_map(definitions, fn def -> + [ + %{index: index_for(def.module).index_name()}, + def.body + ] + end) + + {:ok, %{body: results, status_code: 200}} = + Elastix.Search.search( + opensearch_url(), + "_all", + [], + msearch_body + ) + + results["responses"] + end + + @doc """ + Transforms an index module, query body, and pagination parameters into a query suitable + for submission to the search engine. + + Any of the following functions may be used for submission: + - `search_results/1` + - `msearch_results/1` + - `search_records/2` + - `msearch_records/2` + - `search_records_with_hits/2` + - `msearch_records_with_hits/2` + + ## Example + + iex> Search.search_definition(Image, %{query: %{match_all: %{}}}, %{page_number: 3, page_size: 50}) + %{ + module: Image, + body: %{ + size: 50, + query: %{match_all: %{}}, + from: 100, + _source: false, + track_total_hits: true + }, + page_size: 50, + page_number: 3 + } + + """ + @spec search_definition(index_module(), query_body(), pagination_params()) :: + search_definition() + def search_definition(module, search_query, pagination_params \\ %{}) do + page_number = pagination_params[:page_number] || 1 + page_size = pagination_params[:page_size] || 25 + + search_query = + Map.merge(search_query, %{ + from: (page_number - 1) * page_size, + size: page_size, + _source: false, + track_total_hits: true + }) + + %{ + module: module, + body: search_query, + page_number: page_number, + page_size: page_size + } + end + + defp process_results(results, definition) do + time = results["took"] + count = results["hits"]["total"]["value"] + entries = Enum.map(results["hits"]["hits"], &{String.to_integer(&1["_id"]), &1}) + + Logger.debug("[Search] Query took #{time}ms") + Logger.debug("[Search] #{Jason.encode!(definition.body)}") + + %Scrivener.Page{ + entries: entries, + page_number: definition.page_number, + page_size: definition.page_size, + total_entries: count, + total_pages: div(count + definition.page_size - 1, definition.page_size) + } + end + + @doc """ + Given a search definition generated by `search_definition/3`, submit the query and return + a `m:Scrivener.Page` of results. + + The `entries` in the page are a list of tuples of record IDs paired with the hit that generated + them. + + ## Example + + iex> Search.search_results(definition) + %Scrivener.Page{ + entries: [{1, %{"_id" => "1", ...}}, ...], + page_number: 1, + page_size: 25, + total_entries: 6, + total_pages: 1 + } + + """ + @spec search_results(search_definition()) :: Scrivener.Page.t() + def search_results(definition) do + process_results(search(definition.module, definition.body), definition) + end + + @doc """ + Given a list of search definitions, each generated by `search_definition/3`, submit the query + and return a corresponding list of `m:Scrivener.Page` for each query. + + The `entries` in the page are a list of tuples of record IDs paired with the hit that generated + them. + + ## Example + + iex> Search.msearch_results([definition]) + [ + %Scrivener.Page{ + entries: [{1, %{"_id" => "1", ...}}, ...], + page_number: 1, + page_size: 25, + total_entries: 6, + total_pages: 1 + } + ] + + """ + @spec msearch_results([search_definition()]) :: [Scrivener.Page.t()] + def msearch_results(definitions) do + Enum.map(Enum.zip(msearch(definitions), definitions), fn {result, definition} -> + process_results(result, definition) + end) + end + + defp load_records_from_results(results, ecto_queries) do + Enum.map(Enum.zip(results, ecto_queries), fn {page, ecto_query} -> + {ids, hits} = Enum.unzip(page.entries) + + records = + ecto_query + |> where([m], m.id in ^ids) + |> Repo.all() + |> Enum.sort_by(&Enum.find_index(ids, fn el -> el == &1.id end)) + + %{page | entries: Enum.zip(records, hits)} + end) + end + + @doc """ + Given a search definition generated by `search_definition/3`, submit the query and return a + `m:Scrivener.Page` of results. + + The `entries` in the page are a list of tuples of schema structs paired with the hit that + generated them. + + ## Example + + iex> Search.search_records_with_hits(definition, preload(Image, :tags)) + %Scrivener.Page{ + entries: [{%Image{id: 1, ...}, %{"_id" => "1", ...}}, ...], + page_number: 1, + page_size: 25, + total_entries: 6, + total_pages: 1 + } + + """ + @spec search_records_with_hits(search_definition(), queryable()) :: Scrivener.Page.t() + def search_records_with_hits(definition, ecto_query) do + [page] = load_records_from_results([search_results(definition)], [ecto_query]) + + page + end + + @doc """ + Given a list of search definitions, each generated by `search_definition/3`, submit the query + and return a corresponding list of `m:Scrivener.Page` for each query. + + The `entries` in the page are a list of tuples of schema structs paired with the hit that + generated them. + + ## Example + + iex> Search.msearch_records_with_hits([definition], [preload(Image, :tags)]) + [ + %Scrivener.Page{ + entries: [{%Image{id: 1, ...}, %{"_id" => "1", ...}}, ...], + page_number: 1, + page_size: 25, + total_entries: 6, + total_pages: 1 + } + ] + + """ + @spec msearch_records_with_hits([search_definition()], [queryable()]) :: [Scrivener.Page.t()] + def msearch_records_with_hits(definitions, ecto_queries) do + load_records_from_results(msearch_results(definitions), ecto_queries) + end + + @doc """ + Given a search definition generated by `search_definition/3`, submit the query and return a + `m:Scrivener.Page` of results. + + The `entries` in the page are a list of schema structs. + + ## Example + + iex> Search.search_records(definition, preload(Image, :tags)) + %Scrivener.Page{ + entries: [%Image{id: 1, ...}, ...], + page_number: 1, + page_size: 25, + total_entries: 6, + total_pages: 1 + } + + """ + @spec search_records(search_definition(), queryable()) :: Scrivener.Page.t() + def search_records(definition, ecto_query) do + page = search_records_with_hits(definition, ecto_query) + {records, _hits} = Enum.unzip(page.entries) + + %{page | entries: records} + end + + @doc """ + Given a list of search definitions, each generated by `search_definition/3`, submit the query + and return a corresponding list of `m:Scrivener.Page` for each query. + + The `entries` in the page are a list of schema structs. + + ## Example + + iex> Search.msearch_records([definition], [preload(Image, :tags)]) + [ + %Scrivener.Page{ + entries: [%Image{id: 1, ...}, ...], + page_number: 1, + page_size: 25, + total_entries: 6, + total_pages: 1 + } + ] + + """ + @spec msearch_records([search_definition()], [queryable()]) :: [Scrivener.Page.t()] + def msearch_records(definitions, ecto_queries) do + Enum.map(load_records_from_results(msearch_results(definitions), ecto_queries), fn page -> + {records, _hits} = Enum.unzip(page.entries) + + %{page | entries: records} + end) + end +end diff --git a/lib/philomena/elasticsearch_index.ex b/lib/philomena_query/search_index.ex similarity index 66% rename from lib/philomena/elasticsearch_index.ex rename to lib/philomena_query/search_index.ex index 6810748e..3a4fe9da 100644 --- a/lib/philomena/elasticsearch_index.ex +++ b/lib/philomena_query/search_index.ex @@ -1,4 +1,4 @@ -defmodule Philomena.ElasticsearchIndex do +defmodule PhilomenaQuery.SearchIndex do # Returns the index name for the index. # This is usually a collection name like "images". @callback index_name() :: String.t() @@ -6,7 +6,6 @@ defmodule Philomena.ElasticsearchIndex do # Returns the mapping and settings for the index. @callback mapping() :: map() - # Returns the JSON representation of the given struct - # for indexing in Elasticsearch. + # Returns the JSON representation of the given struct for indexing in OpenSearch. @callback as_json(struct()) :: map() end diff --git a/lib/philomena_web/controllers/activity_controller.ex b/lib/philomena_web/controllers/activity_controller.ex index 9c7dc7ec..45356603 100644 --- a/lib/philomena_web/controllers/activity_controller.ex +++ b/lib/philomena_web/controllers/activity_controller.ex @@ -2,7 +2,7 @@ defmodule PhilomenaWeb.ActivityController do use PhilomenaWeb, :controller alias PhilomenaWeb.ImageLoader - alias Philomena.Elasticsearch + alias PhilomenaQuery.Search alias Philomena.{ Images.Image, @@ -36,7 +36,7 @@ defmodule PhilomenaWeb.ActivityController do ) comments = - Elasticsearch.search_definition( + Search.search_definition( Comment, %{ query: %{ @@ -144,7 +144,7 @@ defmodule PhilomenaWeb.ActivityController do defp multi_search(images, top_scoring, comments, nil) do responses = - Elasticsearch.msearch_records( + Search.msearch_records( [images, top_scoring, comments], [ preload(Image, [:sources, tags: :aliases]), @@ -157,7 +157,7 @@ defmodule PhilomenaWeb.ActivityController do end defp multi_search(images, top_scoring, comments, watched) do - Elasticsearch.msearch_records( + Search.msearch_records( [images, top_scoring, comments, watched], [ preload(Image, [:sources, tags: :aliases]), diff --git a/lib/philomena_web/controllers/admin/report_controller.ex b/lib/philomena_web/controllers/admin/report_controller.ex index 26ea7b5d..e6fc6a97 100644 --- a/lib/philomena_web/controllers/admin/report_controller.ex +++ b/lib/philomena_web/controllers/admin/report_controller.ex @@ -1,7 +1,7 @@ defmodule PhilomenaWeb.Admin.ReportController do use PhilomenaWeb, :controller - alias Philomena.Elasticsearch + alias PhilomenaQuery.Search alias PhilomenaWeb.MarkdownRenderer alias Philomena.Reports.Report alias Philomena.Reports.Query @@ -94,14 +94,14 @@ defmodule PhilomenaWeb.Admin.ReportController do defp load_reports(conn, query) do reports = Report - |> Elasticsearch.search_definition( + |> Search.search_definition( %{ query: query, sort: sorts() }, conn.assigns.pagination ) - |> Elasticsearch.search_records(preload(Report, [:admin, user: :linked_tags])) + |> Search.search_records(preload(Report, [:admin, user: :linked_tags])) entries = Polymorphic.load_polymorphic(reports, reportable: [reportable_id: :reportable_type]) diff --git a/lib/philomena_web/controllers/api/json/search/comment_controller.ex b/lib/philomena_web/controllers/api/json/search/comment_controller.ex index e96ba08d..5dbe5e4c 100644 --- a/lib/philomena_web/controllers/api/json/search/comment_controller.ex +++ b/lib/philomena_web/controllers/api/json/search/comment_controller.ex @@ -1,7 +1,7 @@ defmodule PhilomenaWeb.Api.Json.Search.CommentController do use PhilomenaWeb, :controller - alias Philomena.Elasticsearch + alias PhilomenaQuery.Search alias Philomena.Comments.Comment alias Philomena.Comments.Query import Ecto.Query @@ -14,7 +14,7 @@ defmodule PhilomenaWeb.Api.Json.Search.CommentController do {:ok, query} -> comments = Comment - |> Elasticsearch.search_definition( + |> Search.search_definition( %{ query: %{ bool: %{ @@ -31,7 +31,7 @@ defmodule PhilomenaWeb.Api.Json.Search.CommentController do }, conn.assigns.pagination ) - |> Elasticsearch.search_records(preload(Comment, [:image, :user])) + |> Search.search_records(preload(Comment, [:image, :user])) conn |> put_view(PhilomenaWeb.Api.Json.CommentView) diff --git a/lib/philomena_web/controllers/api/json/search/filter_controller.ex b/lib/philomena_web/controllers/api/json/search/filter_controller.ex index ab9df7fb..7b402065 100644 --- a/lib/philomena_web/controllers/api/json/search/filter_controller.ex +++ b/lib/philomena_web/controllers/api/json/search/filter_controller.ex @@ -1,7 +1,7 @@ defmodule PhilomenaWeb.Api.Json.Search.FilterController do use PhilomenaWeb, :controller - alias Philomena.Elasticsearch + alias PhilomenaQuery.Search alias Philomena.Filters.Filter alias Philomena.Filters.Query import Ecto.Query @@ -13,7 +13,7 @@ defmodule PhilomenaWeb.Api.Json.Search.FilterController do {:ok, query} -> filters = Filter - |> Elasticsearch.search_definition( + |> Search.search_definition( %{ query: %{ bool: %{ @@ -36,7 +36,7 @@ defmodule PhilomenaWeb.Api.Json.Search.FilterController do }, conn.assigns.pagination ) - |> Elasticsearch.search_records(preload(Filter, [:user])) + |> Search.search_records(preload(Filter, [:user])) conn |> put_view(PhilomenaWeb.Api.Json.FilterView) diff --git a/lib/philomena_web/controllers/api/json/search/gallery_controller.ex b/lib/philomena_web/controllers/api/json/search/gallery_controller.ex index d8b8b2ef..8b2f247b 100644 --- a/lib/philomena_web/controllers/api/json/search/gallery_controller.ex +++ b/lib/philomena_web/controllers/api/json/search/gallery_controller.ex @@ -1,7 +1,7 @@ defmodule PhilomenaWeb.Api.Json.Search.GalleryController do use PhilomenaWeb, :controller - alias Philomena.Elasticsearch + alias PhilomenaQuery.Search alias Philomena.Galleries.Gallery alias Philomena.Galleries.Query import Ecto.Query @@ -11,14 +11,14 @@ defmodule PhilomenaWeb.Api.Json.Search.GalleryController do {:ok, query} -> galleries = Gallery - |> Elasticsearch.search_definition( + |> Search.search_definition( %{ query: query, sort: %{created_at: :desc} }, conn.assigns.pagination ) - |> Elasticsearch.search_records(preload(Gallery, [:creator])) + |> Search.search_records(preload(Gallery, [:creator])) conn |> put_view(PhilomenaWeb.Api.Json.GalleryView) diff --git a/lib/philomena_web/controllers/api/json/search/image_controller.ex b/lib/philomena_web/controllers/api/json/search/image_controller.ex index b410dedc..109e7abe 100644 --- a/lib/philomena_web/controllers/api/json/search/image_controller.ex +++ b/lib/philomena_web/controllers/api/json/search/image_controller.ex @@ -2,7 +2,7 @@ defmodule PhilomenaWeb.Api.Json.Search.ImageController do use PhilomenaWeb, :controller alias PhilomenaWeb.ImageLoader - alias Philomena.Elasticsearch + alias PhilomenaQuery.Search alias Philomena.Interactions alias Philomena.Images.Image import Ecto.Query @@ -13,7 +13,7 @@ defmodule PhilomenaWeb.Api.Json.Search.ImageController do case ImageLoader.search_string(conn, params["q"]) do {:ok, {images, _tags}} -> - images = Elasticsearch.search_records(images, queryable) + images = Search.search_records(images, queryable) interactions = Interactions.user_interactions(images, user) conn diff --git a/lib/philomena_web/controllers/api/json/search/post_controller.ex b/lib/philomena_web/controllers/api/json/search/post_controller.ex index 2b39501f..919a5b13 100644 --- a/lib/philomena_web/controllers/api/json/search/post_controller.ex +++ b/lib/philomena_web/controllers/api/json/search/post_controller.ex @@ -1,7 +1,7 @@ defmodule PhilomenaWeb.Api.Json.Search.PostController do use PhilomenaWeb, :controller - alias Philomena.Elasticsearch + alias PhilomenaQuery.Search alias Philomena.Posts.Post alias Philomena.Posts.Query import Ecto.Query @@ -13,7 +13,7 @@ defmodule PhilomenaWeb.Api.Json.Search.PostController do {:ok, query} -> posts = Post - |> Elasticsearch.search_definition( + |> Search.search_definition( %{ query: %{ bool: %{ @@ -28,7 +28,7 @@ defmodule PhilomenaWeb.Api.Json.Search.PostController do }, conn.assigns.pagination ) - |> Elasticsearch.search_records(preload(Post, [:user, :topic])) + |> Search.search_records(preload(Post, [:user, :topic])) conn |> put_view(PhilomenaWeb.Api.Json.Forum.Topic.PostView) diff --git a/lib/philomena_web/controllers/api/json/search/tag_controller.ex b/lib/philomena_web/controllers/api/json/search/tag_controller.ex index 1a765fb1..8cdaf7f4 100644 --- a/lib/philomena_web/controllers/api/json/search/tag_controller.ex +++ b/lib/philomena_web/controllers/api/json/search/tag_controller.ex @@ -1,7 +1,7 @@ defmodule PhilomenaWeb.Api.Json.Search.TagController do use PhilomenaWeb, :controller - alias Philomena.Elasticsearch + alias PhilomenaQuery.Search alias Philomena.Tags.Tag alias Philomena.Tags.Query import Ecto.Query @@ -11,11 +11,11 @@ defmodule PhilomenaWeb.Api.Json.Search.TagController do {:ok, query} -> tags = Tag - |> Elasticsearch.search_definition( + |> Search.search_definition( %{query: query, sort: %{images: :desc}}, conn.assigns.pagination ) - |> Elasticsearch.search_records( + |> Search.search_records( preload(Tag, [:aliased_tag, :aliases, :implied_tags, :implied_by_tags, :dnp_entries]) ) diff --git a/lib/philomena_web/controllers/api/rss/watched_controller.ex b/lib/philomena_web/controllers/api/rss/watched_controller.ex index ba38218e..b2f00f0c 100644 --- a/lib/philomena_web/controllers/api/rss/watched_controller.ex +++ b/lib/philomena_web/controllers/api/rss/watched_controller.ex @@ -3,13 +3,13 @@ defmodule PhilomenaWeb.Api.Rss.WatchedController do alias PhilomenaWeb.ImageLoader alias Philomena.Images.Image - alias Philomena.Elasticsearch + alias PhilomenaQuery.Search import Ecto.Query def index(conn, _params) do {:ok, {images, _tags}} = ImageLoader.search_string(conn, "my:watched") - images = Elasticsearch.search_records(images, preload(Image, [:sources, tags: :aliases])) + images = Search.search_records(images, preload(Image, [:sources, tags: :aliases])) # NB: this is RSS, but using the RSS format causes Phoenix not to # escape HTML diff --git a/lib/philomena_web/controllers/autocomplete/tag_controller.ex b/lib/philomena_web/controllers/autocomplete/tag_controller.ex index 9d43e470..7c06eb59 100644 --- a/lib/philomena_web/controllers/autocomplete/tag_controller.ex +++ b/lib/philomena_web/controllers/autocomplete/tag_controller.ex @@ -1,7 +1,7 @@ defmodule PhilomenaWeb.Autocomplete.TagController do use PhilomenaWeb, :controller - alias Philomena.Elasticsearch + alias PhilomenaQuery.Search alias Philomena.Tags.Tag import Ecto.Query @@ -13,7 +13,7 @@ defmodule PhilomenaWeb.Autocomplete.TagController do term -> Tag - |> Elasticsearch.search_definition( + |> Search.search_definition( %{ query: %{ bool: %{ @@ -27,7 +27,7 @@ defmodule PhilomenaWeb.Autocomplete.TagController do }, %{page_size: 10} ) - |> Elasticsearch.search_records(preload(Tag, :aliased_tag)) + |> Search.search_records(preload(Tag, :aliased_tag)) |> Enum.map(&(&1.aliased_tag || &1)) |> Enum.uniq_by(& &1.id) |> Enum.filter(&(&1.images_count > 0)) diff --git a/lib/philomena_web/controllers/comment_controller.ex b/lib/philomena_web/controllers/comment_controller.ex index ad802c07..99b14f25 100644 --- a/lib/philomena_web/controllers/comment_controller.ex +++ b/lib/philomena_web/controllers/comment_controller.ex @@ -2,7 +2,7 @@ defmodule PhilomenaWeb.CommentController do use PhilomenaWeb, :controller alias PhilomenaWeb.MarkdownRenderer - alias Philomena.Elasticsearch + alias PhilomenaQuery.Search alias Philomena.{Comments.Query, Comments.Comment} import Ecto.Query @@ -21,7 +21,7 @@ defmodule PhilomenaWeb.CommentController do defp render_index({:ok, query}, conn, user) do comments = Comment - |> Elasticsearch.search_definition( + |> Search.search_definition( %{ query: %{ bool: %{ @@ -35,7 +35,7 @@ defmodule PhilomenaWeb.CommentController do }, conn.assigns.pagination ) - |> Elasticsearch.search_records( + |> Search.search_records( preload(Comment, [:deleted_by, image: [:sources, tags: :aliases], user: [awards: :badge]]) ) diff --git a/lib/philomena_web/controllers/filter_controller.ex b/lib/philomena_web/controllers/filter_controller.ex index 9f19415f..61469ffd 100644 --- a/lib/philomena_web/controllers/filter_controller.ex +++ b/lib/philomena_web/controllers/filter_controller.ex @@ -2,7 +2,7 @@ defmodule PhilomenaWeb.FilterController do use PhilomenaWeb, :controller alias Philomena.{Filters, Filters.Filter, Filters.Query, Tags.Tag} - alias Philomena.Elasticsearch + alias PhilomenaQuery.Search alias Philomena.Schema.TagList alias Philomena.Repo import Ecto.Query @@ -47,7 +47,7 @@ defmodule PhilomenaWeb.FilterController do defp render_index({:ok, query}, conn, user) do filters = Filter - |> Elasticsearch.search_definition( + |> Search.search_definition( %{ query: %{ bool: %{ @@ -61,7 +61,7 @@ defmodule PhilomenaWeb.FilterController do }, conn.assigns.pagination ) - |> Elasticsearch.search_records(preload(Filter, [:user])) + |> Search.search_records(preload(Filter, [:user])) render(conn, "index.html", title: "Filters", filters: filters) end diff --git a/lib/philomena_web/controllers/gallery_controller.ex b/lib/philomena_web/controllers/gallery_controller.ex index 2b298d2c..64a020e0 100644 --- a/lib/philomena_web/controllers/gallery_controller.ex +++ b/lib/philomena_web/controllers/gallery_controller.ex @@ -3,7 +3,7 @@ defmodule PhilomenaWeb.GalleryController do alias PhilomenaWeb.ImageLoader alias PhilomenaWeb.NotificationCountPlug - alias Philomena.Elasticsearch + alias PhilomenaQuery.Search alias Philomena.Interactions alias Philomena.Galleries.Gallery alias Philomena.Galleries @@ -21,7 +21,7 @@ defmodule PhilomenaWeb.GalleryController do def index(conn, params) do galleries = Gallery - |> Elasticsearch.search_definition( + |> Search.search_definition( %{ query: %{ bool: %{ @@ -32,7 +32,7 @@ defmodule PhilomenaWeb.GalleryController do }, conn.assigns.pagination ) - |> Elasticsearch.search_records( + |> Search.search_records( preload(Gallery, [:creator, thumbnail: [:sources, tags: :aliases]]) ) @@ -62,7 +62,7 @@ defmodule PhilomenaWeb.GalleryController do {gallery_prev, gallery_next} = prev_next_page_images(conn, query) [images, gallery_prev, gallery_next] = - Elasticsearch.msearch_records_with_hits( + Search.msearch_records_with_hits( [images, gallery_prev, gallery_next], [ preload(Image, [:sources, tags: :aliases]), @@ -154,7 +154,7 @@ defmodule PhilomenaWeb.GalleryController do limit = conn.assigns.image_pagination.page_size offset = (conn.assigns.image_pagination.page_number - 1) * limit - # Inconsistency: Elasticsearch doesn't allow requesting offsets which are less than 0, + # Inconsistency: OpenSearch doesn't allow requesting offsets which are less than 0, # but it does allow requesting offsets which are beyond the total number of results. prev_image = gallery_image(offset - 1, conn, query) @@ -164,7 +164,7 @@ defmodule PhilomenaWeb.GalleryController do end defp gallery_image(offset, _conn, _query) when offset < 0 do - Elasticsearch.search_definition(Image, %{query: %{match_none: %{}}}) + Search.search_definition(Image, %{query: %{match_none: %{}}}) end defp gallery_image(offset, conn, query) do diff --git a/lib/philomena_web/controllers/image/navigate_controller.ex b/lib/philomena_web/controllers/image/navigate_controller.ex index c0827caa..9cb61d48 100644 --- a/lib/philomena_web/controllers/image/navigate_controller.ex +++ b/lib/philomena_web/controllers/image/navigate_controller.ex @@ -4,7 +4,7 @@ defmodule PhilomenaWeb.Image.NavigateController do alias PhilomenaWeb.ImageLoader alias PhilomenaWeb.ImageNavigator alias PhilomenaWeb.ImageScope - alias Philomena.Elasticsearch + alias PhilomenaQuery.Search alias Philomena.Images.Image alias Philomena.Images.Query @@ -37,7 +37,7 @@ defmodule PhilomenaWeb.Image.NavigateController do body = %{range: %{id: %{gt: conn.assigns.image.id}}} {images, _tags} = ImageLoader.query(conn, body, pagination: pagination) - images = Elasticsearch.search_records(images, Image) + images = Search.search_records(images, Image) page_num = page_for_offset(pagination.page_size, images.total_entries) diff --git a/lib/philomena_web/controllers/image/random_controller.ex b/lib/philomena_web/controllers/image/random_controller.ex index 9bc293f7..e104ee40 100644 --- a/lib/philomena_web/controllers/image/random_controller.ex +++ b/lib/philomena_web/controllers/image/random_controller.ex @@ -4,7 +4,7 @@ defmodule PhilomenaWeb.Image.RandomController do alias PhilomenaWeb.ImageSorter alias PhilomenaWeb.ImageScope alias PhilomenaWeb.ImageLoader - alias Philomena.Elasticsearch + alias PhilomenaQuery.Search alias Philomena.Images.Image def index(conn, params) do @@ -32,7 +32,7 @@ defmodule PhilomenaWeb.Image.RandomController do defp unwrap_random_result({:ok, {definition, _tags}}) do definition - |> Elasticsearch.search_records(Image) + |> Search.search_records(Image) |> Enum.to_list() |> unwrap() end diff --git a/lib/philomena_web/controllers/image/related_controller.ex b/lib/philomena_web/controllers/image/related_controller.ex index 2abcbe6b..138d97a9 100644 --- a/lib/philomena_web/controllers/image/related_controller.ex +++ b/lib/philomena_web/controllers/image/related_controller.ex @@ -4,7 +4,7 @@ defmodule PhilomenaWeb.Image.RelatedController do alias PhilomenaWeb.ImageLoader alias Philomena.Interactions alias Philomena.Images.Image - alias Philomena.Elasticsearch + alias PhilomenaQuery.Search import Ecto.Query plug PhilomenaWeb.CanaryMapPlug, index: :show @@ -60,7 +60,7 @@ defmodule PhilomenaWeb.Image.RelatedController do pagination: %{conn.assigns.image_pagination | page_number: 1} ) - images = Elasticsearch.search_records(images, preload(Image, [:sources, tags: :aliases])) + images = Search.search_records(images, preload(Image, [:sources, tags: :aliases])) interactions = Interactions.user_interactions(images, user) diff --git a/lib/philomena_web/controllers/image_controller.ex b/lib/philomena_web/controllers/image_controller.ex index 30364cda..9cb0914a 100644 --- a/lib/philomena_web/controllers/image_controller.ex +++ b/lib/philomena_web/controllers/image_controller.ex @@ -14,7 +14,7 @@ defmodule PhilomenaWeb.ImageController do Galleries.Gallery } - alias Philomena.Elasticsearch + alias PhilomenaQuery.Search alias Philomena.Interactions alias Philomena.Comments alias Philomena.Repo @@ -40,7 +40,7 @@ defmodule PhilomenaWeb.ImageController do {:ok, {images, _tags}} = ImageLoader.search_string(conn, "created_at.lte:3 minutes ago, -thumbnails_generated:false") - images = Elasticsearch.search_records(images, preload(Image, [:sources, tags: :aliases])) + images = Search.search_records(images, preload(Image, [:sources, tags: :aliases])) interactions = Interactions.user_interactions(images, conn.assigns.current_user) diff --git a/lib/philomena_web/controllers/post_controller.ex b/lib/philomena_web/controllers/post_controller.ex index cafcff23..17b8fcd5 100644 --- a/lib/philomena_web/controllers/post_controller.ex +++ b/lib/philomena_web/controllers/post_controller.ex @@ -2,7 +2,7 @@ defmodule PhilomenaWeb.PostController do use PhilomenaWeb, :controller alias PhilomenaWeb.MarkdownRenderer - alias Philomena.Elasticsearch + alias PhilomenaQuery.Search alias Philomena.{Posts.Query, Posts.Post} import Ecto.Query @@ -21,7 +21,7 @@ defmodule PhilomenaWeb.PostController do defp render_index({:ok, query}, conn, user) do posts = Post - |> Elasticsearch.search_definition( + |> Search.search_definition( %{ query: %{ bool: %{ @@ -32,7 +32,7 @@ defmodule PhilomenaWeb.PostController do }, conn.assigns.pagination ) - |> Elasticsearch.search_records( + |> Search.search_records( preload(Post, [:deleted_by, topic: :forum, user: [awards: :badge]]) ) diff --git a/lib/philomena_web/controllers/profile_controller.ex b/lib/philomena_web/controllers/profile_controller.ex index c91ea8d2..b5f1020d 100644 --- a/lib/philomena_web/controllers/profile_controller.ex +++ b/lib/philomena_web/controllers/profile_controller.ex @@ -2,7 +2,7 @@ defmodule PhilomenaWeb.ProfileController do use PhilomenaWeb, :controller alias PhilomenaWeb.ImageLoader - alias Philomena.Elasticsearch + alias PhilomenaQuery.Search alias PhilomenaWeb.MarkdownRenderer alias Philomena.UserStatistics.UserStatistic alias Philomena.Users.User @@ -79,7 +79,7 @@ defmodule PhilomenaWeb.ProfileController do recent_artwork = recent_artwork(conn, tags) recent_comments = - Elasticsearch.search_definition( + Search.search_definition( Comment, %{ query: %{ @@ -100,7 +100,7 @@ defmodule PhilomenaWeb.ProfileController do ) recent_posts = - Elasticsearch.search_definition( + Search.search_definition( Post, %{ query: %{ @@ -119,7 +119,7 @@ defmodule PhilomenaWeb.ProfileController do ) [recent_uploads, recent_faves, recent_artwork, recent_comments, recent_posts] = - Elasticsearch.msearch_records( + Search.msearch_records( [recent_uploads, recent_faves, recent_artwork, recent_comments, recent_posts], [ preload(Image, [:sources, tags: :aliases]), @@ -228,7 +228,7 @@ defmodule PhilomenaWeb.ProfileController do defp tags(links), do: Enum.map(links, & &1.tag) |> Enum.reject(&is_nil/1) defp recent_artwork(_conn, []) do - Elasticsearch.search_definition(Image, %{query: %{match_none: %{}}}) + Search.search_definition(Image, %{query: %{match_none: %{}}}) end defp recent_artwork(conn, tags) do diff --git a/lib/philomena_web/controllers/search_controller.ex b/lib/philomena_web/controllers/search_controller.ex index 969bc096..694a726e 100644 --- a/lib/philomena_web/controllers/search_controller.ex +++ b/lib/philomena_web/controllers/search_controller.ex @@ -3,7 +3,7 @@ defmodule PhilomenaWeb.SearchController do alias PhilomenaWeb.ImageLoader alias Philomena.Images.Image - alias Philomena.Elasticsearch + alias PhilomenaQuery.Search alias Philomena.Interactions import Ecto.Query @@ -41,8 +41,8 @@ defmodule PhilomenaWeb.SearchController do end end - defp search_function(true), do: &Elasticsearch.search_records_with_hits/2 - defp search_function(_custom), do: &Elasticsearch.search_records/2 + defp search_function(true), do: &Search.search_records_with_hits/2 + defp search_function(_custom), do: &Search.search_records/2 defp custom_ordering?(%{params: %{"sf" => sf}}) when sf != "id", do: true defp custom_ordering?(_conn), do: false diff --git a/lib/philomena_web/controllers/tag_controller.ex b/lib/philomena_web/controllers/tag_controller.ex index 2c94d3e5..162393bb 100644 --- a/lib/philomena_web/controllers/tag_controller.ex +++ b/lib/philomena_web/controllers/tag_controller.ex @@ -2,7 +2,7 @@ defmodule PhilomenaWeb.TagController do use PhilomenaWeb, :controller alias PhilomenaWeb.ImageLoader - alias Philomena.Elasticsearch + alias PhilomenaQuery.Search alias Philomena.{Tags, Tags.Tag} alias Philomena.{Images, Images.Image} alias PhilomenaWeb.MarkdownRenderer @@ -34,7 +34,7 @@ defmodule PhilomenaWeb.TagController do with {:ok, query} <- Tags.Query.compile(query_string) do tags = Tag - |> Elasticsearch.search_definition( + |> Search.search_definition( %{ query: query, size: 250, @@ -42,7 +42,7 @@ defmodule PhilomenaWeb.TagController do }, %{conn.assigns.pagination | page_size: 250} ) - |> Elasticsearch.search_records(Tag) + |> Search.search_records(Tag) render(conn, "index.html", title: "Tags", tags: tags) else @@ -57,7 +57,7 @@ defmodule PhilomenaWeb.TagController do {images, _tags} = ImageLoader.query(conn, %{term: %{"namespaced_tags.name" => tag.name}}) - images = Elasticsearch.search_records(images, preload(Image, [:sources, tags: :aliases])) + images = Search.search_records(images, preload(Image, [:sources, tags: :aliases])) interactions = Interactions.user_interactions(images, user) diff --git a/lib/philomena_web/image_loader.ex b/lib/philomena_web/image_loader.ex index c6a33c2a..d2bc80ea 100644 --- a/lib/philomena_web/image_loader.ex +++ b/lib/philomena_web/image_loader.ex @@ -1,6 +1,6 @@ defmodule PhilomenaWeb.ImageLoader do alias PhilomenaWeb.ImageSorter - alias Philomena.Elasticsearch + alias PhilomenaQuery.Search alias Philomena.Images.{Image, Query} alias PhilomenaWeb.MarkdownRenderer alias Philomena.Tags.Tag @@ -36,7 +36,7 @@ defmodule PhilomenaWeb.ImageLoader do %{query: query, sorts: sort} = sorts.(body) definition = - Elasticsearch.search_definition( + Search.search_definition( Image, %{ query: %{ diff --git a/lib/philomena_web/image_navigator.ex b/lib/philomena_web/image_navigator.ex index fce68944..547fb617 100644 --- a/lib/philomena_web/image_navigator.ex +++ b/lib/philomena_web/image_navigator.ex @@ -1,7 +1,7 @@ defmodule PhilomenaWeb.ImageNavigator do alias PhilomenaWeb.ImageSorter alias Philomena.Images.Image - alias Philomena.Elasticsearch + alias PhilomenaQuery.Search @order_for_dir %{ "next" => %{"asc" => "asc", "desc" => "desc"}, @@ -54,8 +54,8 @@ defmodule PhilomenaWeb.ImageNavigator do defp maybe_search_after(module, body, options, queryable, true) do module - |> Elasticsearch.search_definition(body, options) - |> Elasticsearch.search_records_with_hits(queryable) + |> Search.search_definition(body, options) + |> Search.search_records_with_hits(queryable) end defp maybe_search_after(_module, _body, _options, _queryable, _false) do diff --git a/lib/philomena_web/plugs/filter_forced_users_plug.ex b/lib/philomena_web/plugs/filter_forced_users_plug.ex index 17d1886c..e28de969 100644 --- a/lib/philomena_web/plugs/filter_forced_users_plug.ex +++ b/lib/philomena_web/plugs/filter_forced_users_plug.ex @@ -6,8 +6,8 @@ defmodule PhilomenaWeb.FilterForcedUsersPlug do import Phoenix.Controller import Plug.Conn - alias Philomena.Search.String, as: SearchString - alias Philomena.Search.Evaluator + alias PhilomenaQuery.Parse.String, as: SearchString + alias PhilomenaQuery.Parse.Evaluator alias Philomena.Images.Query alias PhilomenaWeb.ImageView diff --git a/lib/philomena_web/plugs/image_filter_plug.ex b/lib/philomena_web/plugs/image_filter_plug.ex index 3281d0e8..c8138d68 100644 --- a/lib/philomena_web/plugs/image_filter_plug.ex +++ b/lib/philomena_web/plugs/image_filter_plug.ex @@ -1,6 +1,6 @@ defmodule PhilomenaWeb.ImageFilterPlug do import Plug.Conn - import Philomena.Search.String + import PhilomenaQuery.Parse.String alias Philomena.Images.Query diff --git a/lib/philomena_web/stats_updater.ex b/lib/philomena_web/stats_updater.ex index dc53324d..8eec95c5 100644 --- a/lib/philomena_web/stats_updater.ex +++ b/lib/philomena_web/stats_updater.ex @@ -1,6 +1,6 @@ defmodule PhilomenaWeb.StatsUpdater do alias Philomena.Config - alias Philomena.Elasticsearch + alias PhilomenaQuery.Search alias Philomena.Images.Image alias Philomena.Comments.Comment alias Philomena.Topics.Topic @@ -68,8 +68,8 @@ defmodule PhilomenaWeb.StatsUpdater do data = Config.get(:aggregation) { - Elasticsearch.search(Image, data["images"]), - Elasticsearch.search(Comment, data["comments"]) + Search.search(Image, data["images"]), + Search.search(Comment, data["comments"]) } end diff --git a/lib/philomena_web/views/api/json/image_view.ex b/lib/philomena_web/views/api/json/image_view.ex index 924ae86b..d6c8b951 100644 --- a/lib/philomena_web/views/api/json/image_view.ex +++ b/lib/philomena_web/views/api/json/image_view.ex @@ -71,7 +71,7 @@ defmodule PhilomenaWeb.Api.Json.ImageView do tag_ids: Enum.map(image.tags, & &1.id), uploader: if(!!image.user and !image.anonymous, do: image.user.name), uploader_id: if(!!image.user and !image.anonymous, do: image.user.id), - wilson_score: Philomena.Images.ElasticsearchIndex.wilson_score(image), + wilson_score: Philomena.Images.SearchIndex.wilson_score(image), intensities: intensities(image), score: image.score, upvotes: image.upvotes_count, diff --git a/lib/philomena_web/views/image_view.ex b/lib/philomena_web/views/image_view.ex index dc9d9be8..4a69af5e 100644 --- a/lib/philomena_web/views/image_view.ex +++ b/lib/philomena_web/views/image_view.ex @@ -291,7 +291,7 @@ defmodule PhilomenaWeb.ImageView do } } - Philomena.Search.Evaluator.hits?(doc, query) + PhilomenaQuery.Parse.Evaluator.hits?(doc, query) end def image_source_icon(nil), do: "fa fa-link" diff --git a/lib/philomena_web/views/layout_view.ex b/lib/philomena_web/views/layout_view.ex index b9c2210b..b2cfd06f 100644 --- a/lib/philomena_web/views/layout_view.ex +++ b/lib/philomena_web/views/layout_view.ex @@ -43,9 +43,9 @@ defmodule PhilomenaWeb.LayoutView do data = [ filter_id: filter.id, hidden_tag_list: Jason.encode!(filter.hidden_tag_ids), - hidden_filter: Philomena.Search.String.normalize(filter.hidden_complex_str || ""), + hidden_filter: PhilomenaQuery.Parse.String.normalize(filter.hidden_complex_str || ""), spoilered_tag_list: Jason.encode!(filter.spoilered_tag_ids), - spoilered_filter: Philomena.Search.String.normalize(filter.spoilered_complex_str || ""), + spoilered_filter: PhilomenaQuery.Parse.String.normalize(filter.spoilered_complex_str || ""), user_id: if(user, do: user.id, else: nil), user_name: if(user, do: user.name, else: nil), user_slug: if(user, do: user.slug, else: nil), diff --git a/lib/philomena_web/views/tag_view.ex b/lib/philomena_web/views/tag_view.ex index bcbc1e22..ef860d71 100644 --- a/lib/philomena_web/views/tag_view.ex +++ b/lib/philomena_web/views/tag_view.ex @@ -3,7 +3,7 @@ defmodule PhilomenaWeb.TagView do # this is bad practice, don't copy this. alias Philomena.Config - alias Philomena.Elasticsearch + alias PhilomenaQuery.Search alias Philomena.Tags.Tag alias Philomena.Repo alias PhilomenaWeb.ImageScope @@ -143,7 +143,7 @@ defmodule PhilomenaWeb.TagView do defp implied_by_multitag(tag_names, ignore_tag_names) do Tag - |> Elasticsearch.search_definition( + |> Search.search_definition( %{ query: %{ bool: %{ @@ -155,7 +155,7 @@ defmodule PhilomenaWeb.TagView do }, %{page_size: 40} ) - |> Elasticsearch.search_records(preload(Tag, :implied_tags)) + |> Search.search_records(preload(Tag, :implied_tags)) end defp manages_links?(conn), diff --git a/priv/repo/seeds.exs b/priv/repo/seeds.exs index ad09bcea..1fe20dcd 100644 --- a/priv/repo/seeds.exs +++ b/priv/repo/seeds.exs @@ -26,17 +26,17 @@ alias Philomena.{ StaticPages.StaticPage } -alias Philomena.Elasticsearch +alias PhilomenaQuery.Search alias Philomena.Users alias Philomena.Tags alias Philomena.Filters import Ecto.Query -IO.puts("---- Creating Elasticsearch indices") +IO.puts("---- Creating search indices") for model <- [Image, Comment, Gallery, Tag, Post, Report, Filter] do - Elasticsearch.delete_index!(model) - Elasticsearch.create_index!(model) + Search.delete_index!(model) + Search.create_index!(model) end resources = @@ -112,6 +112,6 @@ for page_def <- resources["pages"] do end IO.puts("---- Indexing content") -Elasticsearch.reindex(Tag |> preload(^Tags.indexing_preloads()), Tag) +Search.reindex(Tag |> preload(^Tags.indexing_preloads()), Tag) IO.puts("---- Done.") From 9b204c908dd5cd2f1841b8a26a7c20626db6ebf0 Mon Sep 17 00:00:00 2001 From: Liam Date: Sat, 1 Jun 2024 23:03:34 -0400 Subject: [PATCH 34/35] More fully separate underlying search behavior from usage in application --- lib/philomena/search_policy.ex | 55 +++++++++++++++++++++ lib/philomena_query/search.ex | 87 ++++++++++++---------------------- 2 files changed, 86 insertions(+), 56 deletions(-) create mode 100644 lib/philomena/search_policy.ex diff --git a/lib/philomena/search_policy.ex b/lib/philomena/search_policy.ex new file mode 100644 index 00000000..d753026a --- /dev/null +++ b/lib/philomena/search_policy.ex @@ -0,0 +1,55 @@ +defmodule Philomena.SearchPolicy do + alias Philomena.Comments.Comment + alias Philomena.Galleries.Gallery + alias Philomena.Images.Image + alias Philomena.Posts.Post + alias Philomena.Reports.Report + alias Philomena.Tags.Tag + alias Philomena.Filters.Filter + + alias Philomena.Comments.SearchIndex, as: CommentIndex + alias Philomena.Galleries.SearchIndex, as: GalleryIndex + alias Philomena.Images.SearchIndex, as: ImageIndex + alias Philomena.Posts.SearchIndex, as: PostIndex + alias Philomena.Reports.SearchIndex, as: ReportIndex + alias Philomena.Tags.SearchIndex, as: TagIndex + alias Philomena.Filters.SearchIndex, as: FilterIndex + + @type schema_module :: Comment | Gallery | Image | Post | Report | Tag | Filter + + @doc """ + For a given schema module (e.g. `m:Philomena.Images.Image`), return the associated module + which implements the `SearchIndex` behaviour (e.g. `m:Philomena.Images.SearchIndex`). + + ## Example + + iex> SearchPolicy.index_for(Gallery) + Philomena.Galleries.SearchIndex + + iex> SearchPolicy.index_for(:foo) + ** (FunctionClauseError) no function clause matching in Philomena.SearchPolicy.index_for/1 + + """ + @spec index_for(schema_module()) :: module() + def index_for(Comment), do: CommentIndex + def index_for(Gallery), do: GalleryIndex + def index_for(Image), do: ImageIndex + def index_for(Post), do: PostIndex + def index_for(Report), do: ReportIndex + def index_for(Tag), do: TagIndex + def index_for(Filter), do: FilterIndex + + @doc """ + Return the path used to interact with the search engine. + + ## Example + + iex> SearchPolicy.opensearch_url() + "http://localhost:9200" + + """ + @spec opensearch_url :: String.t() + def opensearch_url do + Application.get_env(:philomena, :opensearch_url) + end +end diff --git a/lib/philomena_query/search.ex b/lib/philomena_query/search.ex index 13a34f44..b4960657 100644 --- a/lib/philomena_query/search.ex +++ b/lib/philomena_query/search.ex @@ -15,35 +15,10 @@ defmodule PhilomenaQuery.Search do import Ecto.Query import Elastix.HTTP - alias Philomena.Comments.Comment - alias Philomena.Galleries.Gallery - alias Philomena.Images.Image - alias Philomena.Posts.Post - alias Philomena.Reports.Report - alias Philomena.Tags.Tag - alias Philomena.Filters.Filter + # todo: fetch through compile_env? + @policy Philomena.SearchPolicy - alias Philomena.Comments.SearchIndex, as: CommentIndex - alias Philomena.Galleries.SearchIndex, as: GalleryIndex - alias Philomena.Images.SearchIndex, as: ImageIndex - alias Philomena.Posts.SearchIndex, as: PostIndex - alias Philomena.Reports.SearchIndex, as: ReportIndex - alias Philomena.Tags.SearchIndex, as: TagIndex - alias Philomena.Filters.SearchIndex, as: FilterIndex - - defp index_for(Comment), do: CommentIndex - defp index_for(Gallery), do: GalleryIndex - defp index_for(Image), do: ImageIndex - defp index_for(Post), do: PostIndex - defp index_for(Report), do: ReportIndex - defp index_for(Tag), do: TagIndex - defp index_for(Filter), do: FilterIndex - - defp opensearch_url do - Application.get_env(:philomena, :opensearch_url) - end - - @type index_module :: module() + @type schema_module :: @policy.schema_module() @type queryable :: any() @type query_body :: map() @@ -54,7 +29,7 @@ defmodule PhilomenaQuery.Search do } @type search_definition :: %{ - module: index_module(), + module: schema_module(), body: query_body(), page_number: integer(), page_size: integer() @@ -80,12 +55,12 @@ defmodule PhilomenaQuery.Search do iex> Search.create_index!(Image) """ - @spec create_index!(index_module()) :: any() + @spec create_index!(schema_module()) :: any() def create_index!(module) do - index = index_for(module) + index = @policy.index_for(module) Elastix.Index.create( - opensearch_url(), + @policy.opensearch_url(), index.index_name(), index.mapping() ) @@ -104,11 +79,11 @@ defmodule PhilomenaQuery.Search do iex> Search.delete_index!(Image) """ - @spec delete_index!(index_module()) :: any() + @spec delete_index!(schema_module()) :: any() def delete_index!(module) do - index = index_for(module) + index = @policy.index_for(module) - Elastix.Index.delete(opensearch_url(), index.index_name()) + Elastix.Index.delete(@policy.opensearch_url(), index.index_name()) end @doc ~S""" @@ -124,14 +99,14 @@ defmodule PhilomenaQuery.Search do iex> Search.update_mapping!(Image) """ - @spec update_mapping!(index_module()) :: any() + @spec update_mapping!(schema_module()) :: any() def update_mapping!(module) do - index = index_for(module) + index = @policy.index_for(module) index_name = index.index_name() mapping = index.mapping().mappings.properties - Elastix.Mapping.put(opensearch_url(), index_name, "_doc", %{properties: mapping}, + Elastix.Mapping.put(@policy.opensearch_url(), index_name, "_doc", %{properties: mapping}, include_type_name: true ) end @@ -151,13 +126,13 @@ defmodule PhilomenaQuery.Search do iex> Search.index_document(%Image{...}, Image) """ - @spec index_document(struct(), index_module()) :: any() + @spec index_document(struct(), schema_module()) :: any() def index_document(doc, module) do - index = index_for(module) + index = @policy.index_for(module) data = index.as_json(doc) Elastix.Document.index( - opensearch_url(), + @policy.opensearch_url(), index.index_name(), "_doc", data.id, @@ -181,12 +156,12 @@ defmodule PhilomenaQuery.Search do iex> Search.delete_document(image.id, Image) """ - @spec delete_document(term(), index_module()) :: any() + @spec delete_document(term(), schema_module()) :: any() def delete_document(id, module) do - index = index_for(module) + index = @policy.index_for(module) Elastix.Document.delete( - opensearch_url(), + @policy.opensearch_url(), index.index_name(), "_doc", id @@ -215,9 +190,9 @@ defmodule PhilomenaQuery.Search do Search.reindex(query, Image, batch_size: 5000) """ - @spec reindex(queryable(), index_module(), Batch.batch_options()) :: [] + @spec reindex(queryable(), schema_module(), Batch.batch_options()) :: [] def reindex(queryable, module, opts \\ []) do - index = index_for(module) + index = @policy.index_for(module) Batch.record_batches(queryable, opts, fn records -> lines = @@ -231,7 +206,7 @@ defmodule PhilomenaQuery.Search do end) Elastix.Bulk.post( - opensearch_url(), + @policy.opensearch_url(), lines, index: index.index_name(), httpoison_options: [timeout: 30_000] @@ -267,12 +242,12 @@ defmodule PhilomenaQuery.Search do Search.update_by_query(Post, query_body, [set_replacement], []) """ - @spec update_by_query(index_module(), query_body(), [replacement()], [replacement()]) :: any() + @spec update_by_query(schema_module(), query_body(), [replacement()], [replacement()]) :: any() def update_by_query(module, query_body, set_replacements, replacements) do - index = index_for(module) + index = @policy.index_for(module) url = - opensearch_url() + @policy.opensearch_url() |> prepare_url([index.index_name(), "_update_by_query"]) |> append_query_string(%{conflicts: "proceed", wait_for_completion: "false"}) @@ -355,13 +330,13 @@ defmodule PhilomenaQuery.Search do } """ - @spec search(index_module(), query_body()) :: map() + @spec search(schema_module(), query_body()) :: map() def search(module, query_body) do - index = index_for(module) + index = @policy.index_for(module) {:ok, %{body: results, status_code: 200}} = Elastix.Search.search( - opensearch_url(), + @policy.opensearch_url(), index.index_name(), [], query_body @@ -395,14 +370,14 @@ defmodule PhilomenaQuery.Search do msearch_body = Enum.flat_map(definitions, fn def -> [ - %{index: index_for(def.module).index_name()}, + %{index: @policy.index_for(def.module).index_name()}, def.body ] end) {:ok, %{body: results, status_code: 200}} = Elastix.Search.search( - opensearch_url(), + @policy.opensearch_url(), "_all", [], msearch_body @@ -440,7 +415,7 @@ defmodule PhilomenaQuery.Search do } """ - @spec search_definition(index_module(), query_body(), pagination_params()) :: + @spec search_definition(schema_module(), query_body(), pagination_params()) :: search_definition() def search_definition(module, search_query, pagination_params \\ %{}) do page_number = pagination_params[:page_number] || 1 From c8d696540f7d1d6fb322ab5522647456ccef8078 Mon Sep 17 00:00:00 2001 From: Liam Date: Sun, 2 Jun 2024 00:15:09 -0400 Subject: [PATCH 35/35] Split out media processing tools into PhilomenaMedia namespace --- lib/mix/tasks/upload_to_s3.ex | 2 +- lib/philomena/adverts/uploader.ex | 2 +- lib/philomena/analyzers.ex | 56 --- lib/philomena/badges/uploader.ex | 2 +- lib/philomena/filename.ex | 21 - lib/philomena/image_intensities.ex | 6 +- lib/philomena/images/thumbnailer.ex | 11 +- lib/philomena/images/uploader.ex | 2 +- lib/philomena/intensities.ex | 23 -- lib/philomena/mime.ex | 37 -- lib/philomena/objects.ex | 148 ------- lib/philomena/processors.ex | 78 ---- lib/philomena/tags/uploader.ex | 2 +- lib/philomena/uploader.ex | 125 ------ lib/philomena/users/uploader.ex | 2 +- lib/philomena_media/analyzers.ex | 71 ++++ lib/philomena_media/analyzers/analyzer.ex | 5 + .../analyzers/gif.ex | 12 +- .../analyzers/jpeg.ex | 12 +- .../analyzers/png.ex | 12 +- lib/philomena_media/analyzers/result.ex | 36 ++ .../analyzers/svg.ex | 12 +- .../analyzers/webm.ex | 12 +- lib/philomena_media/filename.ex | 36 ++ lib/philomena_media/intensities.ex | 68 ++++ lib/philomena_media/mime.ex | 67 ++++ lib/philomena_media/objects.ex | 236 ++++++++++++ lib/philomena_media/processors.ex | 202 ++++++++++ .../processors/gif.ex | 21 +- .../processors/jpeg.ex | 21 +- .../processors/png.ex | 23 +- lib/philomena_media/processors/processor.ex | 21 + .../processors/svg.ex | 21 +- .../processors/webm.ex | 21 +- lib/{philomena => philomena_media}/sha512.ex | 17 +- lib/philomena_media/uploader.ex | 360 ++++++++++++++++++ lib/philomena_web/image_reverse.ex | 4 +- 37 files changed, 1266 insertions(+), 541 deletions(-) delete mode 100644 lib/philomena/analyzers.ex delete mode 100644 lib/philomena/filename.ex delete mode 100644 lib/philomena/intensities.ex delete mode 100644 lib/philomena/mime.ex delete mode 100644 lib/philomena/objects.ex delete mode 100644 lib/philomena/processors.ex delete mode 100644 lib/philomena/uploader.ex create mode 100644 lib/philomena_media/analyzers.ex create mode 100644 lib/philomena_media/analyzers/analyzer.ex rename lib/{philomena => philomena_media}/analyzers/gif.ex (74%) rename lib/{philomena => philomena_media}/analyzers/jpeg.ex (73%) rename lib/{philomena => philomena_media}/analyzers/png.ex (74%) create mode 100644 lib/philomena_media/analyzers/result.ex rename lib/{philomena => philomena_media}/analyzers/svg.ex (71%) rename lib/{philomena => philomena_media}/analyzers/webm.ex (74%) create mode 100644 lib/philomena_media/filename.ex create mode 100644 lib/philomena_media/intensities.ex create mode 100644 lib/philomena_media/mime.ex create mode 100644 lib/philomena_media/objects.ex create mode 100644 lib/philomena_media/processors.ex rename lib/{philomena => philomena_media}/processors/gif.ex (83%) rename lib/{philomena => philomena_media}/processors/jpeg.ex (79%) rename lib/{philomena => philomena_media}/processors/png.ex (74%) create mode 100644 lib/philomena_media/processors/processor.ex rename lib/{philomena => philomena_media}/processors/svg.ex (66%) rename lib/{philomena => philomena_media}/processors/webm.ex (90%) rename lib/{philomena => philomena_media}/sha512.ex (63%) create mode 100644 lib/philomena_media/uploader.ex diff --git a/lib/mix/tasks/upload_to_s3.ex b/lib/mix/tasks/upload_to_s3.ex index ae6b22fd..87ab48d3 100644 --- a/lib/mix/tasks/upload_to_s3.ex +++ b/lib/mix/tasks/upload_to_s3.ex @@ -10,7 +10,7 @@ defmodule Mix.Tasks.UploadToS3 do } alias Philomena.Images.Thumbnailer - alias Philomena.Objects + alias PhilomenaMedia.Objects alias PhilomenaQuery.Batch import Ecto.Query diff --git a/lib/philomena/adverts/uploader.ex b/lib/philomena/adverts/uploader.ex index 5260e415..d575ebe4 100644 --- a/lib/philomena/adverts/uploader.ex +++ b/lib/philomena/adverts/uploader.ex @@ -4,7 +4,7 @@ defmodule Philomena.Adverts.Uploader do """ alias Philomena.Adverts.Advert - alias Philomena.Uploader + alias PhilomenaMedia.Uploader def analyze_upload(advert, params) do Uploader.analyze_upload(advert, "image", params["image"], &Advert.image_changeset/2) diff --git a/lib/philomena/analyzers.ex b/lib/philomena/analyzers.ex deleted file mode 100644 index 1a3961ec..00000000 --- a/lib/philomena/analyzers.ex +++ /dev/null @@ -1,56 +0,0 @@ -defmodule Philomena.Analyzers do - @moduledoc """ - Utilities for analyzing the format and various attributes of uploaded files. - """ - - alias Philomena.Mime - - alias Philomena.Analyzers.Gif - alias Philomena.Analyzers.Jpeg - alias Philomena.Analyzers.Png - alias Philomena.Analyzers.Svg - alias Philomena.Analyzers.Webm - - @doc """ - Returns an {:ok, analyzer} tuple, with the analyzer being a module capable - of analyzing this content type, or :error. - - To use an analyzer, call the analyze/1 method on it with the path to the - file. It will return a map such as the following: - - %{ - animated?: false, - dimensions: {800, 600}, - duration: 0.0, - extension: "png", - mime_type: "image/png" - } - """ - @spec analyzer(binary()) :: {:ok, module()} | :error - def analyzer(content_type) - - def analyzer("image/gif"), do: {:ok, Gif} - def analyzer("image/jpeg"), do: {:ok, Jpeg} - def analyzer("image/png"), do: {:ok, Png} - def analyzer("image/svg+xml"), do: {:ok, Svg} - def analyzer("video/webm"), do: {:ok, Webm} - def analyzer(_content_type), do: :error - - @doc """ - Attempts a mime check and analysis on the given pathname or Plug.Upload. - """ - @spec analyze(Plug.Upload.t() | String.t()) :: {:ok, map()} | :error - def analyze(%Plug.Upload{path: path}), do: analyze(path) - - def analyze(path) when is_binary(path) do - with {:ok, mime} <- Mime.file(path), - {:ok, analyzer} <- analyzer(mime) do - {:ok, analyzer.analyze(path)} - else - error -> - error - end - end - - def analyze(_path), do: :error -end diff --git a/lib/philomena/badges/uploader.ex b/lib/philomena/badges/uploader.ex index 8ab44f9f..6410bae9 100644 --- a/lib/philomena/badges/uploader.ex +++ b/lib/philomena/badges/uploader.ex @@ -4,7 +4,7 @@ defmodule Philomena.Badges.Uploader do """ alias Philomena.Badges.Badge - alias Philomena.Uploader + alias PhilomenaMedia.Uploader def analyze_upload(badge, params) do Uploader.analyze_upload(badge, "image", params["image"], &Badge.image_changeset/2) diff --git a/lib/philomena/filename.ex b/lib/philomena/filename.ex deleted file mode 100644 index ea0d230d..00000000 --- a/lib/philomena/filename.ex +++ /dev/null @@ -1,21 +0,0 @@ -defmodule Philomena.Filename do - @moduledoc """ - Utilities for building arbitrary filenames for uploaded files. - """ - - @spec build(String.t()) :: String.t() - def build(extension) do - [ - time_identifier(DateTime.utc_now()), - "/", - UUID.uuid1(), - ".", - extension - ] - |> Enum.join() - end - - defp time_identifier(time) do - Enum.join([time.year, time.month, time.day], "/") - end -end diff --git a/lib/philomena/image_intensities.ex b/lib/philomena/image_intensities.ex index 5a4d130b..34c311d5 100644 --- a/lib/philomena/image_intensities.ex +++ b/lib/philomena/image_intensities.ex @@ -36,9 +36,9 @@ defmodule Philomena.ImageIntensities do {:error, %Ecto.Changeset{}} """ - def create_image_intensity(image, attrs \\ %{}) do + def create_image_intensity(image, attrs \\ %PhilomenaMedia.Intensities{}) do %ImageIntensity{image_id: image.id} - |> ImageIntensity.changeset(attrs) + |> ImageIntensity.changeset(Map.from_struct(attrs)) |> Repo.insert() end @@ -56,7 +56,7 @@ defmodule Philomena.ImageIntensities do """ def update_image_intensity(%ImageIntensity{} = image_intensity, attrs) do image_intensity - |> ImageIntensity.changeset(attrs) + |> ImageIntensity.changeset(Map.from_struct(attrs)) |> Repo.update() end diff --git a/lib/philomena/images/thumbnailer.ex b/lib/philomena/images/thumbnailer.ex index d6d5cc8e..8c566135 100644 --- a/lib/philomena/images/thumbnailer.ex +++ b/lib/philomena/images/thumbnailer.ex @@ -3,15 +3,16 @@ defmodule Philomena.Images.Thumbnailer do Prevewing and thumbnailing logic for Images. """ + alias PhilomenaMedia.Processors + alias PhilomenaMedia.Analyzers + alias PhilomenaMedia.Uploader + alias PhilomenaMedia.Objects + alias PhilomenaMedia.Sha512 + alias Philomena.DuplicateReports alias Philomena.ImageIntensities alias Philomena.ImagePurgeWorker alias Philomena.Images.Image - alias Philomena.Processors - alias Philomena.Analyzers - alias Philomena.Uploader - alias Philomena.Objects - alias Philomena.Sha512 alias Philomena.Repo @versions [ diff --git a/lib/philomena/images/uploader.ex b/lib/philomena/images/uploader.ex index 39111e11..3c54a7db 100644 --- a/lib/philomena/images/uploader.ex +++ b/lib/philomena/images/uploader.ex @@ -5,7 +5,7 @@ defmodule Philomena.Images.Uploader do alias Philomena.Images.Thumbnailer alias Philomena.Images.Image - alias Philomena.Uploader + alias PhilomenaMedia.Uploader def analyze_upload(image, params) do Uploader.analyze_upload(image, "image", params["image"], &Image.image_changeset/2) diff --git a/lib/philomena/intensities.ex b/lib/philomena/intensities.ex deleted file mode 100644 index 250d0fea..00000000 --- a/lib/philomena/intensities.ex +++ /dev/null @@ -1,23 +0,0 @@ -defmodule Philomena.Intensities do - @doc """ - Gets the corner intensities of the given image file. - The image file must be in the PNG or JPEG format. - """ - @spec file(String.t()) :: {:ok, map()} | :error - def file(input) do - System.cmd("image-intensities", [input]) - |> case do - {output, 0} -> - [nw, ne, sw, se] = - output - |> String.trim() - |> String.split("\t") - |> Enum.map(&String.to_float/1) - - {:ok, %{nw: nw, ne: ne, sw: sw, se: se}} - - _error -> - :error - end - end -end diff --git a/lib/philomena/mime.ex b/lib/philomena/mime.ex deleted file mode 100644 index 08d5dfc1..00000000 --- a/lib/philomena/mime.ex +++ /dev/null @@ -1,37 +0,0 @@ -defmodule Philomena.Mime do - @type mime :: String.t() - - @doc """ - Gets the mime type of the given pathname. - """ - @spec file(String.t()) :: {:ok, mime()} | :error - def file(path) do - System.cmd("file", ["-b", "--mime-type", path]) - |> case do - {output, 0} -> - true_mime(String.trim(output)) - - _error -> - :error - end - end - - @doc """ - Provides the "true" content type of this file. - - Some files are identified incorrectly as a mime type they should not be. - These incorrect mime types (and their "corrected") versions are: - - - image/svg -> image/svg+xml - - audio/webm -> video/webm - """ - @spec true_mime(String.t()) :: {:ok, mime()} - def true_mime("image/svg"), do: {:ok, "image/svg+xml"} - def true_mime("audio/webm"), do: {:ok, "video/webm"} - - def true_mime(mime) - when mime in ~W(image/gif image/jpeg image/png image/svg+xml video/webm), - do: {:ok, mime} - - def true_mime(mime), do: {:unsupported_mime, mime} -end diff --git a/lib/philomena/objects.ex b/lib/philomena/objects.ex deleted file mode 100644 index 3df94142..00000000 --- a/lib/philomena/objects.ex +++ /dev/null @@ -1,148 +0,0 @@ -defmodule Philomena.Objects do - @moduledoc """ - Replication wrapper for object storage backends. - """ - alias Philomena.Mime - require Logger - - # - # Fetch a key from the storage backend and - # write it into the destination file. - # - # sobelow_skip ["Traversal.FileModule"] - @spec download_file(String.t(), String.t()) :: any() - def download_file(key, file_path) do - contents = - backends() - |> Enum.find_value(fn opts -> - ExAws.S3.get_object(opts[:bucket], key) - |> ExAws.request(opts[:config_overrides]) - |> case do - {:ok, result} -> result - _ -> nil - end - end) - - File.write!(file_path, contents.body) - end - - # - # Upload a file using a single API call, writing the - # contents from the given path to storage. - # - # sobelow_skip ["Traversal.FileModule"] - @spec put(String.t(), String.t()) :: any() - def put(key, file_path) do - {_, mime} = Mime.file(file_path) - contents = File.read!(file_path) - - run_all(fn opts -> - ExAws.S3.put_object(opts[:bucket], key, contents, content_type: mime) - |> ExAws.request!(opts[:config_overrides]) - end) - end - - # - # Upload a file using multiple API calls, writing the - # contents from the given path to storage. - # - @spec upload(String.t(), String.t()) :: any() - def upload(key, file_path) do - # Workaround for API rate limit issues on R2 - put(key, file_path) - end - - # - # Copies a key from the source to the destination, - # overwriting the destination object if its exists. - # - @spec copy(String.t(), String.t()) :: any() - def copy(source_key, dest_key) do - # Potential workaround for inconsistent PutObjectCopy on R2 - # - # run_all(fn opts-> - # ExAws.S3.put_object_copy(opts[:bucket], dest_key, opts[:bucket], source_key) - # |> ExAws.request!(opts[:config_overrides]) - # end) - - try do - file_path = Briefly.create!() - download_file(source_key, file_path) - upload(dest_key, file_path) - catch - _kind, _value -> Logger.warning("Failed to copy #{source_key} -> #{dest_key}") - end - end - - # - # Removes the key from storage. - # - @spec delete(String.t()) :: any() - def delete(key) do - run_all(fn opts -> - ExAws.S3.delete_object(opts[:bucket], key) - |> ExAws.request!(opts[:config_overrides]) - end) - end - - # - # Removes all given keys from storage. - # - @spec delete_multiple([String.t()]) :: any() - def delete_multiple(keys) do - run_all(fn opts -> - ExAws.S3.delete_multiple_objects(opts[:bucket], keys) - |> ExAws.request!(opts[:config_overrides]) - end) - end - - defp run_all(wrapped) do - fun = fn opts -> - try do - wrapped.(opts) - :ok - catch - _kind, _value -> :error - end - end - - backends() - |> Task.async_stream(fun, timeout: :infinity) - |> Enum.any?(fn {_, v} -> v == :error end) - |> case do - true -> - Logger.warning("Failed to operate on all backends") - - _ -> - :ok - end - end - - defp backends do - primary_opts() ++ replica_opts() - end - - defp primary_opts do - [ - %{ - config_overrides: Application.fetch_env!(:philomena, :s3_primary_options), - bucket: Application.fetch_env!(:philomena, :s3_primary_bucket) - } - ] - end - - defp replica_opts do - replica_bucket = Application.get_env(:philomena, :s3_secondary_bucket) - - if not is_nil(replica_bucket) do - [ - %{ - config_overrides: Application.fetch_env!(:philomena, :s3_secondary_options), - bucket: replica_bucket - } - ] - else - [] - end - end -end diff --git a/lib/philomena/processors.ex b/lib/philomena/processors.ex deleted file mode 100644 index 202da1d4..00000000 --- a/lib/philomena/processors.ex +++ /dev/null @@ -1,78 +0,0 @@ -defmodule Philomena.Processors do - @moduledoc """ - Utilities for processing uploads. - - Processors have 3 methods available: - - - process/3: - Takes an analysis, file path, and version list and generates an - "edit script" that represents how to store this file according to the - given version list. See Philomena.Images.Thumbnailer for more - information on how this works. - - - post_process/2: - Takes an analysis and file path and performs optimizations on the - upload. See Philomena.Images.Thumbnailer for more information on how this - works. - - - intensities/2: - Takes an analysis and file path and generates an intensities map - appropriate for use by Philomena.DuplicateReports. - """ - - alias Philomena.Processors.Gif - alias Philomena.Processors.Jpeg - alias Philomena.Processors.Png - alias Philomena.Processors.Svg - alias Philomena.Processors.Webm - - @doc """ - Returns a processor, with the processor being a module capable - of processing this content type, or nil. - """ - @spec processor(String.t()) :: module() | nil - def processor(content_type) - - def processor("image/gif"), do: Gif - def processor("image/jpeg"), do: Jpeg - def processor("image/png"), do: Png - def processor("image/svg+xml"), do: Svg - def processor("video/webm"), do: Webm - def processor(_content_type), do: nil - - @doc """ - Takes a MIME type and version list and generates a list of versions to be - generated (e.g., ["thumb.png"]). List contents differ based on file type. - """ - @spec versions(String.t(), keyword) :: [String.t()] - def versions(mime_type, valid_sizes) do - processor(mime_type).versions(valid_sizes) - end - - @doc """ - Takes an analyzer, file path, and version list and runs the appropriate - processor's process/3. - """ - @spec process(map(), String.t(), keyword) :: map() - def process(analysis, file, versions) do - processor(analysis.mime_type).process(analysis, file, versions) - end - - @doc """ - Takes an analyzer and file path and runs the appropriate processor's - post_process/2. - """ - @spec post_process(map(), String.t()) :: map() - def post_process(analysis, file) do - processor(analysis.mime_type).post_process(analysis, file) - end - - @doc """ - Takes an analyzer and file path and runs the appropriate processor's - intensities/2. - """ - @spec intensities(map(), String.t()) :: map() - def intensities(analysis, file) do - processor(analysis.mime_type).intensities(analysis, file) - end -end diff --git a/lib/philomena/tags/uploader.ex b/lib/philomena/tags/uploader.ex index d6149221..d7ab63d6 100644 --- a/lib/philomena/tags/uploader.ex +++ b/lib/philomena/tags/uploader.ex @@ -4,7 +4,7 @@ defmodule Philomena.Tags.Uploader do """ alias Philomena.Tags.Tag - alias Philomena.Uploader + alias PhilomenaMedia.Uploader def analyze_upload(tag, params) do Uploader.analyze_upload(tag, "image", params["image"], &Tag.image_changeset/2) diff --git a/lib/philomena/uploader.ex b/lib/philomena/uploader.ex deleted file mode 100644 index df982897..00000000 --- a/lib/philomena/uploader.ex +++ /dev/null @@ -1,125 +0,0 @@ -defmodule Philomena.Uploader do - @moduledoc """ - Upload and processing callback logic for image files. - """ - - alias Philomena.Filename - alias Philomena.Analyzers - alias Philomena.Objects - alias Philomena.Sha512 - import Ecto.Changeset - - @doc """ - Performs analysis of the passed Plug.Upload, and invokes a changeset - callback on the model or changeset passed in with attributes set on - the field_name. - """ - @spec analyze_upload(any(), String.t(), Plug.Upload.t(), (any(), map() -> Ecto.Changeset.t())) :: - Ecto.Changeset.t() - def analyze_upload(model_or_changeset, field_name, upload_parameter, changeset_fn) do - with {:ok, analysis} <- Analyzers.analyze(upload_parameter), - analysis <- extra_attributes(analysis, upload_parameter) do - removed = - model_or_changeset - |> change() - |> get_field(field(field_name)) - - attributes = - %{ - "name" => analysis.name, - "width" => analysis.width, - "height" => analysis.height, - "size" => analysis.size, - "format" => analysis.extension, - "mime_type" => analysis.mime_type, - "duration" => analysis.duration, - "aspect_ratio" => analysis.aspect_ratio, - "orig_sha512_hash" => analysis.sha512, - "sha512_hash" => analysis.sha512, - "is_animated" => analysis.animated? - } - |> prefix_attributes(field_name) - |> Map.put(field_name, analysis.new_name) - |> Map.put(upload_key(field_name), upload_parameter.path) - |> Map.put(remove_key(field_name), removed) - - changeset_fn.(model_or_changeset, attributes) - else - {:unsupported_mime, mime} -> - attributes = prefix_attributes(%{"mime_type" => mime}, field_name) - changeset_fn.(model_or_changeset, attributes) - - _error -> - changeset_fn.(model_or_changeset, %{}) - end - end - - @doc """ - Writes the file to permanent storage. This should be the second-to-last step - in the transaction. - """ - @spec persist_upload(any(), String.t(), String.t()) :: any() - def persist_upload(model, file_root, field_name) do - source = Map.get(model, field(upload_key(field_name))) - dest = Map.get(model, field(field_name)) - target = Path.join(file_root, dest) - - persist_file(target, source) - end - - @doc """ - Persist an arbitrary file to storage at the given path with the correct - content type and permissions. - """ - def persist_file(path, file) do - Objects.upload(path, file) - end - - @doc """ - Removes the old file from permanent storage. This should be the last step in - the transaction. - """ - @spec unpersist_old_upload(any(), String.t(), String.t()) :: any() - def unpersist_old_upload(model, file_root, field_name) do - model - |> Map.get(field(remove_key(field_name))) - |> try_remove(file_root) - end - - defp extra_attributes(analysis, %Plug.Upload{path: path, filename: filename}) do - {width, height} = analysis.dimensions - aspect_ratio = aspect_ratio(width, height) - - stat = File.stat!(path) - sha512 = Sha512.file(path) - new_name = Filename.build(analysis.extension) - - analysis - |> Map.put(:size, stat.size) - |> Map.put(:name, filename) - |> Map.put(:width, width) - |> Map.put(:height, height) - |> Map.put(:sha512, sha512) - |> Map.put(:new_name, new_name) - |> Map.put(:aspect_ratio, aspect_ratio) - end - - defp aspect_ratio(_, 0), do: 0.0 - defp aspect_ratio(w, h), do: w / h - - defp try_remove("", _file_root), do: nil - defp try_remove(nil, _file_root), do: nil - - defp try_remove(file, file_root) do - Objects.delete(Path.join(file_root, file)) - end - - defp prefix_attributes(map, prefix), - do: Map.new(map, fn {key, value} -> {"#{prefix}_#{key}", value} end) - - defp upload_key(field_name), do: "uploaded_#{field_name}" - - defp remove_key(field_name), do: "removed_#{field_name}" - - defp field(field_name), do: String.to_existing_atom(field_name) -end diff --git a/lib/philomena/users/uploader.ex b/lib/philomena/users/uploader.ex index 9d8cb1cb..7e6f0ced 100644 --- a/lib/philomena/users/uploader.ex +++ b/lib/philomena/users/uploader.ex @@ -4,7 +4,7 @@ defmodule Philomena.Users.Uploader do """ alias Philomena.Users.User - alias Philomena.Uploader + alias PhilomenaMedia.Uploader def analyze_upload(user, params) do Uploader.analyze_upload(user, "avatar", params["avatar"], &User.avatar_changeset/2) diff --git a/lib/philomena_media/analyzers.ex b/lib/philomena_media/analyzers.ex new file mode 100644 index 00000000..a010916f --- /dev/null +++ b/lib/philomena_media/analyzers.ex @@ -0,0 +1,71 @@ +defmodule PhilomenaMedia.Analyzers do + @moduledoc """ + Utilities for analyzing the format and various attributes of uploaded files. + """ + + alias PhilomenaMedia.Analyzers.{Gif, Jpeg, Png, Svg, Webm} + alias PhilomenaMedia.Analyzers.Result + alias PhilomenaMedia.Mime + + @doc """ + Returns an `{:ok, analyzer}` tuple, with the analyzer being a module capable + of analyzing this media type, or `:error`. + + The allowed MIME types are: + - `image/gif` + - `image/jpeg` + - `image/png` + - `image/svg+xml` + - `video/webm` + + > #### Info {: .info} + > + > This is an interface intended for use when the MIME type is already known. + > Using an analyzer not matched to the file may cause unexpected results. + + ## Examples + + {:ok, analyzer} = PhilomenaMedia.Analyzers.analyzer("image/png") + :error = PhilomenaMedia.Analyzers.analyzer("application/octet-stream") + + """ + @spec analyzer(Mime.t()) :: {:ok, module()} | :error + def analyzer(content_type) + + def analyzer("image/gif"), do: {:ok, Gif} + def analyzer("image/jpeg"), do: {:ok, Jpeg} + def analyzer("image/png"), do: {:ok, Png} + def analyzer("image/svg+xml"), do: {:ok, Svg} + def analyzer("video/webm"), do: {:ok, Webm} + def analyzer(_content_type), do: :error + + @doc """ + Attempts a MIME type check and analysis on the given path or `m:Plug.Upload`. + + ## Examples + + file = "image_file.png" + {:ok, %Result{...}} = Analyzers.analyze(file) + + file = %Plug.Upload{...} + {:ok, %Result{...}} = Analyzers.analyze(file) + + file = "text_file.txt" + :error = Analyzers.analyze(file) + + """ + @spec analyze(Plug.Upload.t() | Path.t()) :: {:ok, Result.t()} | :error + def analyze(%Plug.Upload{path: path}), do: analyze(path) + + def analyze(path) when is_binary(path) do + with {:ok, mime} <- Mime.file(path), + {:ok, analyzer} <- analyzer(mime) do + {:ok, analyzer.analyze(path)} + else + error -> + error + end + end + + def analyze(_path), do: :error +end diff --git a/lib/philomena_media/analyzers/analyzer.ex b/lib/philomena_media/analyzers/analyzer.ex new file mode 100644 index 00000000..cf3b28ec --- /dev/null +++ b/lib/philomena_media/analyzers/analyzer.ex @@ -0,0 +1,5 @@ +defmodule PhilomenaMedia.Analyzers.Analyzer do + @moduledoc false + + @callback analyze(Path.t()) :: PhilomenaMedia.Analyzers.Result.t() +end diff --git a/lib/philomena/analyzers/gif.ex b/lib/philomena_media/analyzers/gif.ex similarity index 74% rename from lib/philomena/analyzers/gif.ex rename to lib/philomena_media/analyzers/gif.ex index 2253ac04..982d7a31 100644 --- a/lib/philomena/analyzers/gif.ex +++ b/lib/philomena_media/analyzers/gif.ex @@ -1,8 +1,16 @@ -defmodule Philomena.Analyzers.Gif do +defmodule PhilomenaMedia.Analyzers.Gif do + @moduledoc false + + alias PhilomenaMedia.Analyzers.Analyzer + alias PhilomenaMedia.Analyzers.Result + + @behaviour Analyzer + + @spec analyze(Path.t()) :: Result.t() def analyze(file) do stats = stats(file) - %{ + %Result{ extension: "gif", mime_type: "image/gif", animated?: stats.animated?, diff --git a/lib/philomena/analyzers/jpeg.ex b/lib/philomena_media/analyzers/jpeg.ex similarity index 73% rename from lib/philomena/analyzers/jpeg.ex rename to lib/philomena_media/analyzers/jpeg.ex index c73564b7..60b29e04 100644 --- a/lib/philomena/analyzers/jpeg.ex +++ b/lib/philomena_media/analyzers/jpeg.ex @@ -1,8 +1,16 @@ -defmodule Philomena.Analyzers.Jpeg do +defmodule PhilomenaMedia.Analyzers.Jpeg do + @moduledoc false + + alias PhilomenaMedia.Analyzers.Analyzer + alias PhilomenaMedia.Analyzers.Result + + @behaviour Analyzer + + @spec analyze(Path.t()) :: Result.t() def analyze(file) do stats = stats(file) - %{ + %Result{ extension: "jpg", mime_type: "image/jpeg", animated?: false, diff --git a/lib/philomena/analyzers/png.ex b/lib/philomena_media/analyzers/png.ex similarity index 74% rename from lib/philomena/analyzers/png.ex rename to lib/philomena_media/analyzers/png.ex index 30d3bc9b..83cb506f 100644 --- a/lib/philomena/analyzers/png.ex +++ b/lib/philomena_media/analyzers/png.ex @@ -1,8 +1,16 @@ -defmodule Philomena.Analyzers.Png do +defmodule PhilomenaMedia.Analyzers.Png do + @moduledoc false + + alias PhilomenaMedia.Analyzers.Analyzer + alias PhilomenaMedia.Analyzers.Result + + @behaviour Analyzer + + @spec analyze(Path.t()) :: Result.t() def analyze(file) do stats = stats(file) - %{ + %Result{ extension: "png", mime_type: "image/png", animated?: stats.animated?, diff --git a/lib/philomena_media/analyzers/result.ex b/lib/philomena_media/analyzers/result.ex new file mode 100644 index 00000000..57dc77c0 --- /dev/null +++ b/lib/philomena_media/analyzers/result.ex @@ -0,0 +1,36 @@ +defmodule PhilomenaMedia.Analyzers.Result do + @moduledoc """ + The analysis result. + + - `:animated?` - whether the media file is animated + - `:dimensions` - the maximum dimensions of the media file, as `{width, height}` + - `:duration` - the maximum duration of the media file, or 0 if not applicable + - `:extension` - the file extension the media file should take, based on its contents + - `:mime_type` - the MIME type the media file should take, based on its contents + + ## Example + + %Result{ + animated?: false, + dimensions: {800, 600}, + duration: 0.0, + extension: "png", + mime_type: "image/png" + } + + """ + + @type t :: %__MODULE__{ + animated?: boolean(), + dimensions: {integer(), integer()}, + duration: float(), + extension: String.t(), + mime_type: String.t() + } + + defstruct animated?: false, + dimensions: {0, 0}, + duration: 0.0, + extension: "", + mime_type: "application/octet-stream" +end diff --git a/lib/philomena/analyzers/svg.ex b/lib/philomena_media/analyzers/svg.ex similarity index 71% rename from lib/philomena/analyzers/svg.ex rename to lib/philomena_media/analyzers/svg.ex index d76aab4b..f83a55f0 100644 --- a/lib/philomena/analyzers/svg.ex +++ b/lib/philomena_media/analyzers/svg.ex @@ -1,8 +1,16 @@ -defmodule Philomena.Analyzers.Svg do +defmodule PhilomenaMedia.Analyzers.Svg do + @moduledoc false + + alias PhilomenaMedia.Analyzers.Analyzer + alias PhilomenaMedia.Analyzers.Result + + @behaviour Analyzer + + @spec analyze(Path.t()) :: Result.t() def analyze(file) do stats = stats(file) - %{ + %Result{ extension: "svg", mime_type: "image/svg+xml", animated?: false, diff --git a/lib/philomena/analyzers/webm.ex b/lib/philomena_media/analyzers/webm.ex similarity index 74% rename from lib/philomena/analyzers/webm.ex rename to lib/philomena_media/analyzers/webm.ex index 236978b1..b215e01e 100644 --- a/lib/philomena/analyzers/webm.ex +++ b/lib/philomena_media/analyzers/webm.ex @@ -1,8 +1,16 @@ -defmodule Philomena.Analyzers.Webm do +defmodule PhilomenaMedia.Analyzers.Webm do + @moduledoc false + + alias PhilomenaMedia.Analyzers.Analyzer + alias PhilomenaMedia.Analyzers.Result + + @behaviour Analyzer + + @spec analyze(Path.t()) :: Result.t() def analyze(file) do stats = stats(file) - %{ + %Result{ extension: "webm", mime_type: "video/webm", animated?: stats.animated?, diff --git a/lib/philomena_media/filename.ex b/lib/philomena_media/filename.ex new file mode 100644 index 00000000..ba169fe4 --- /dev/null +++ b/lib/philomena_media/filename.ex @@ -0,0 +1,36 @@ +defmodule PhilomenaMedia.Filename do + @moduledoc """ + Utilities for building arbitrary filenames for uploaded files. + """ + + @type extension :: String.t() + + @doc """ + This function builds a replacement "filename key" based on the supplied file extension. + + Names are generated in the form `year/month/day/uuid.ext`. It is recommended to avoid + providing user-controlled file-extensions to this function; select them from a list of + known extensions instead. + + ## Example + + iex> PhilomenaMedia.Filename.build("png") + "2024/1/1/0bce8eea-17e0-11ef-b7d4-0242ac120006.png" + + """ + @spec build(extension()) :: String.t() + def build(extension) do + [ + time_identifier(DateTime.utc_now()), + "/", + UUID.uuid1(), + ".", + extension + ] + |> Enum.join() + end + + defp time_identifier(time) do + Enum.join([time.year, time.month, time.day], "/") + end +end diff --git a/lib/philomena_media/intensities.ex b/lib/philomena_media/intensities.ex new file mode 100644 index 00000000..5abd71e0 --- /dev/null +++ b/lib/philomena_media/intensities.ex @@ -0,0 +1,68 @@ +defmodule PhilomenaMedia.Intensities do + @moduledoc """ + Corner intensities are a simple mechanism for automatic image deduplication, + designed for a time when computer vision was an expensive technology and + resources were scarce. + + Each image is divided into quadrants; image with odd numbers of pixels + on either dimension overlap quadrants by one pixel. The luma (brightness) + value corresponding each the pixel is computed according to BTU.709 primaries, + and its value is added to a sum for each quadrant. Finally, the value is divided + by the number of pixels in the quadrant to produce an average. The minimum luma + value of any pixel is 0, and the maximum is 255, so an average will be between + these values. Transparent pixels are composited on black before processing. + + By using a range search in the database, this produces a reverse image search which + suffers no dimensionality issues, is exceptionally fast to evaluate, and is independent + of image dimensions, with poor precision and a poor-to-fair accuracy. + """ + + @type t :: %__MODULE__{ + nw: float(), + ne: float(), + sw: float(), + se: float() + } + + defstruct nw: 0.0, + ne: 0.0, + sw: 0.0, + se: 0.0 + + @doc """ + Gets the corner intensities of the given image file. + + The image file must be in the PNG or JPEG format. + + > #### Info {: .info} + > + > Clients should prefer to use `m:PhilomenaMedia.Processors.intensities/2`, as it handles + > media files of any type supported by this library, not just PNG or JPEG. + + ## Examples + + iex> Intensities.file("image.png") + {:ok, %Intensities{nw: 111.689148, ne: 116.228048, sw: 93.268433, se: 104.630064}} + + iex> Intensities.file("nonexistent.jpg") + :error + + """ + @spec file(Path.t()) :: {:ok, t()} | :error + def file(input) do + System.cmd("image-intensities", [input]) + |> case do + {output, 0} -> + [nw, ne, sw, se] = + output + |> String.trim() + |> String.split("\t") + |> Enum.map(&String.to_float/1) + + {:ok, %__MODULE__{nw: nw, ne: ne, sw: sw, se: se}} + + _error -> + :error + end + end +end diff --git a/lib/philomena_media/mime.ex b/lib/philomena_media/mime.ex new file mode 100644 index 00000000..1b29aa75 --- /dev/null +++ b/lib/philomena_media/mime.ex @@ -0,0 +1,67 @@ +defmodule PhilomenaMedia.Mime do + @moduledoc """ + Utilities for determining the MIME type of a file via parsing. + + Many MIME type libraries assume the MIME type of the file by reading file extensions. + This is inherently unreliable, as many websites disguise the content types of files with + specific names for cost or bandwidth saving reasons. As processing depends on correctly + identifying the type of a file, parsing the file contents is necessary. + """ + + @type t :: String.t() + + @doc """ + Gets the MIME type of the given pathname. + + ## Examples + + iex> PhilomenaMedia.Mime.file("image.png") + {:ok, "image/png"} + + iex> PhilomenaMedia.Mime.file("file.txt") + {:unsupported_mime, "text/plain"} + + iex> PhilomenaMedia.Mime.file("nonexistent.file") + :error + + """ + @spec file(Path.t()) :: {:ok, t()} | {:unsupported_mime, t()} | :error + def file(path) do + System.cmd("file", ["-b", "--mime-type", path]) + |> case do + {output, 0} -> + true_mime(String.trim(output)) + + _error -> + :error + end + end + + @doc """ + Provides the "true" MIME type of this file. + + Some files are identified as a type they should not be based on how they are used by + this library. These MIME types (and their "corrected") versions are: + + - `image/svg` -> `image/svg+xml` + - `audio/webm` -> `video/webm` + + ## Examples + + iex> PhilomenaMedia.Mime.file("image.svg") + "image/svg+xml" + + iex> PhilomenaMedia.Mime.file("audio.webm") + "video/webm" + + """ + @spec true_mime(String.t()) :: {:ok, t()} | {:unsupported_mime, t()} + def true_mime("image/svg"), do: {:ok, "image/svg+xml"} + def true_mime("audio/webm"), do: {:ok, "video/webm"} + + def true_mime(mime) + when mime in ~W(image/gif image/jpeg image/png image/svg+xml video/webm), + do: {:ok, mime} + + def true_mime(mime), do: {:unsupported_mime, mime} +end diff --git a/lib/philomena_media/objects.ex b/lib/philomena_media/objects.ex new file mode 100644 index 00000000..27a92732 --- /dev/null +++ b/lib/philomena_media/objects.ex @@ -0,0 +1,236 @@ +defmodule PhilomenaMedia.Objects do + @moduledoc """ + Replication wrapper for object storage backends. + + While cloud services can be an inexpensive way to access large amounts of storage, they + are inherently less available than local file-based storage. For this reason, it is generally + recommended to maintain a secondary storage provider, such as in the + [3-2-1 backup strategy](https://www.backblaze.com/blog/the-3-2-1-backup-strategy/). + + Functions in this module replicate operations on both the primary and secondary storage + providers. Alternatively, a mode with only a primary storage provider is supported. + + This module assumes storage endpoints are S3-compatible and can be communicated with via the + `m:ExAws` module. This does not preclude the usage of local file-based storage, which can be + accomplished with the [`s3proxy` project](https://github.com/gaul/s3proxy). The development + repository provides an example of `s3proxy` in use. + + Bucket names should be set with configuration on `s3_primary_bucket` and `s3_secondary_bucket`. + If `s3_secondary_bucket` is not set, then only the primary will be used. However, the primary + bucket name must always be set. + + These are read from environment variables at runtime by Philomena. + + # S3/Object store config + config :philomena, :s3_primary_bucket, System.fetch_env!("S3_BUCKET") + config :philomena, :s3_secondary_bucket, System.get_env("ALT_S3_BUCKET") + + Additional options (e.g. controlling the remote endpoint used) may be set with + `s3_primary_options` and `s3_secondary_options` keys. This allows you to use a provider other + than AWS, like [Cloudflare R2](https://developers.cloudflare.com/r2/). + + These are read from environment variables at runtime by Philomena. + + config :philomena, :s3_primary_options, + region: System.get_env("S3_REGION", "us-east-1"), + scheme: System.fetch_env!("S3_SCHEME"), + host: System.fetch_env!("S3_HOST"), + port: System.fetch_env!("S3_PORT"), + access_key_id: System.fetch_env!("AWS_ACCESS_KEY_ID"), + secret_access_key: System.fetch_env!("AWS_SECRET_ACCESS_KEY"), + http_opts: [timeout: 180_000, recv_timeout: 180_000] + + """ + alias PhilomenaMedia.Mime + require Logger + + @type key :: String.t() + + @doc """ + Fetch a key from the storage backend and write it into the destination path. + + ## Example + + key = "2024/1/1/5/full.png" + Objects.download_file(key, file_path) + + """ + # sobelow_skip ["Traversal.FileModule"] + @spec download_file(key(), Path.t()) :: :ok + def download_file(key, file_path) do + contents = + backends() + |> Enum.find_value(fn opts -> + ExAws.S3.get_object(opts[:bucket], key) + |> ExAws.request(opts[:config_overrides]) + |> case do + {:ok, result} -> result + _ -> nil + end + end) + + File.write!(file_path, contents.body) + end + + @doc """ + Upload a file using a single API call, writing the contents from the given path to storage. + + ## Example + + key = "2024/1/1/5/full.png" + Objects.put(key, file_path) + + """ + # sobelow_skip ["Traversal.FileModule"] + @spec put(key(), Path.t()) :: :ok + def put(key, file_path) do + {_, mime} = Mime.file(file_path) + contents = File.read!(file_path) + + run_all(fn opts -> + ExAws.S3.put_object(opts[:bucket], key, contents, content_type: mime) + |> ExAws.request!(opts[:config_overrides]) + end) + end + + @doc """ + Upload a file using multiple API calls, writing the contents from the given path to storage. + + ## Example + + key = "2024/1/1/5/full.png" + Objects.upload(key, file_path) + + """ + @spec upload(key(), Path.t()) :: :ok + def upload(key, file_path) do + # Workaround for API rate limit issues on R2 + put(key, file_path) + end + + @doc """ + Copies a key from the source to the destination, overwriting the destination object if its exists. + + > #### Warning {: .warning} + > + > `copy/2` does not use the `PutObjectCopy` S3 request. It downloads the file and uploads it again. + > This may use more disk space than expected if the file is large. + + ## Example + + source_key = "2024/1/1/5/full.png" + dest_key = "2024/1/1/5-a5323e542e0f/full.png" + Objects.copy(source_key, dest_key) + + """ + @spec copy(key(), key()) :: :ok + def copy(source_key, dest_key) do + # Potential workaround for inconsistent PutObjectCopy on R2 + # + # run_all(fn opts-> + # ExAws.S3.put_object_copy(opts[:bucket], dest_key, opts[:bucket], source_key) + # |> ExAws.request!(opts[:config_overrides]) + # end) + + try do + file_path = Briefly.create!() + download_file(source_key, file_path) + upload(dest_key, file_path) + catch + _kind, _value -> Logger.warning("Failed to copy #{source_key} -> #{dest_key}") + end + + :ok + end + + @doc """ + Removes the key from storage. + + ## Example + + key = "2024/1/1/5/full.png" + Objects.delete(key) + + """ + @spec delete(key()) :: :ok + def delete(key) do + run_all(fn opts -> + ExAws.S3.delete_object(opts[:bucket], key) + |> ExAws.request!(opts[:config_overrides]) + end) + end + + @doc """ + Removes all given keys from storage. + + ## Example + + keys = [ + "2024/1/1/5/full.png", + "2024/1/1/5/small.png", + "2024/1/1/5/thumb.png", + "2024/1/1/5/thumb_tiny.png" + ] + Objects.delete_multiple(keys) + + """ + @spec delete_multiple([key()]) :: :ok + def delete_multiple(keys) do + run_all(fn opts -> + ExAws.S3.delete_multiple_objects(opts[:bucket], keys) + |> ExAws.request!(opts[:config_overrides]) + end) + end + + defp run_all(wrapped) do + fun = fn opts -> + try do + wrapped.(opts) + :ok + catch + _kind, _value -> :error + end + end + + backends() + |> Task.async_stream(fun, timeout: :infinity) + |> Enum.any?(fn {_, v} -> v == :error end) + |> case do + true -> + Logger.warning("Failed to operate on all backends") + + _ -> + :ok + end + + :ok + end + + defp backends do + primary_opts() ++ replica_opts() + end + + defp primary_opts do + [ + %{ + config_overrides: Application.fetch_env!(:philomena, :s3_primary_options), + bucket: Application.fetch_env!(:philomena, :s3_primary_bucket) + } + ] + end + + defp replica_opts do + replica_bucket = Application.get_env(:philomena, :s3_secondary_bucket) + + if not is_nil(replica_bucket) do + [ + %{ + config_overrides: Application.fetch_env!(:philomena, :s3_secondary_options), + bucket: replica_bucket + } + ] + else + [] + end + end +end diff --git a/lib/philomena_media/processors.ex b/lib/philomena_media/processors.ex new file mode 100644 index 00000000..23c49dcf --- /dev/null +++ b/lib/philomena_media/processors.ex @@ -0,0 +1,202 @@ +defmodule PhilomenaMedia.Processors do + @moduledoc """ + Utilities for processing uploads. + + Processors have 4 functions available: + + - `versions/1`: + Takes a version list and generates a list of files which the processor will generate + during the scope of `process/3`. + + - `process/3`: + Takes an analysis result, file path, and version list and generates an "edit script" that + represents how to store this file according to the given version list. See + `m:Philomena.Images.Thumbnailer` for a usage example. + + - `post_process/2`: + Takes an analysis result and file path and performs optimizations on the upload. See + `m:Philomena.Images.Thumbnailer` for a usage example. + + - `intensities/2`: + Takes an analysis result and file path and generates corner intensities, performing. + any conversion necessary before processing. See `m:PhilomenaMedia.Intensities` + for more information. + + ## Version lists + + `process/3` and `post_process/2` take _version lists_ as input. A version list is a structure + like the following, which contains pairs of _version names_ and _dimensions_: + + [ + thumb_tiny: {50, 50}, + thumb_small: {150, 150}, + thumb: {250, 250}, + small: {320, 240}, + medium: {800, 600}, + large: {1280, 1024}, + tall: {1024, 4096} + ] + + When calling these functions, it is recommended prefilter the version list based on the media + dimensions to avoid generating unnecessary versions which are larger than the original file. + See `m:Philomena.Images.Thumbnailer` for an example. + + ## Edit scripts + + `process/3` and `post_process/2` return _edit scripts_. An edit script is a list where each + entry may be one of the following: + + {:thumbnails, [copy_requests]} + {:replace_original, path} + {:intensities, intensities} + + Within the thumbnail request, a copy request is defined with the following structure: + + {:copy, path, version_filename} + + See the respective functions for more information about their return values. + """ + + alias PhilomenaMedia.Analyzers.Result + alias PhilomenaMedia.Intensities + alias PhilomenaMedia.Processors.{Gif, Jpeg, Png, Svg, Webm} + alias PhilomenaMedia.Mime + + # The name of a version, like :large + @type version_name :: atom() + + @type dimensions :: {integer(), integer()} + @type version_list :: [{version_name(), dimensions()}] + + # The file name of a processed version, like "large.png" + @type version_filename :: String.t() + + # A single file to be copied to satisfy a request for a version name + @type copy_request :: {:copy, Path.t(), version_filename()} + + # A list of thumbnail versions to copy into place + @type thumbnails :: {:thumbnails, [copy_request()]} + + # Replace the original file to strip metadata or losslessly optimize + @type replace_original :: {:replace_original, Path.t()} + + # Apply the computed corner intensities + @type intensities :: {:intensities, Intensities.t()} + + # An edit script, representing the changes to apply to the storage backend + # after successful processing + @type edit_script :: [thumbnails() | replace_original() | intensities()] + + @doc """ + Returns a processor, with the processor being a module capable + of processing this content type, or nil. + + The allowed MIME types are: + - `image/gif` + - `image/jpeg` + - `image/png` + - `image/svg+xml` + - `video/webm` + + > #### Info {: .info} + > + > This is an interface intended for use when the MIME type is already known. + > Using a processor not matched to the file may cause unexpected results. + + ## Examples + + iex> PhilomenaMedia.Processors.processor("image/png") + PhilomenaMedia.Processors.Png + + iex> PhilomenaMedia.Processors.processor("application/octet-stream") + nil + + """ + @spec processor(Mime.t()) :: module() | nil + def processor(content_type) + + def processor("image/gif"), do: Gif + def processor("image/jpeg"), do: Jpeg + def processor("image/png"), do: Png + def processor("image/svg+xml"), do: Svg + def processor("video/webm"), do: Webm + def processor(_content_type), do: nil + + @doc """ + Takes a MIME type and filtered version list and generates a list of version files to be + generated by `process/2`. List contents may differ based on file type. + + ## Examples + + iex> PhilomenaMedia.Processors.versions("image/png", [thumb_tiny: {50, 50}]) + ["thumb_tiny.png"] + + iex> PhilomenaMedia.Processors.versions("video/webm", [thumb_tiny: {50, 50}]) + ["full.mp4", "rendered.png", "thumb_tiny.webm", "thumb_tiny.mp4", "thumb_tiny.gif"] + + """ + @spec versions(Mime.t(), version_list()) :: [version_name()] + def versions(mime_type, valid_sizes) do + processor(mime_type).versions(valid_sizes) + end + + @doc """ + Takes an analyzer result, file path, and version list and runs the appropriate processor's + `process/3`, processing the media. + + Returns an edit script to apply changes. Depending on the media type, this make take a long + time to execute. + + ## Example + + iex> PhilomenaMedia.Processors.process(%Result{...}, "image.png", [thumb_tiny: {50, 50}]) + [ + intensities: %Intensities{...}, + thumbnails: [ + {:copy, "/tmp/briefly-5764/vSHsM3kn7k4yvrvZH.png", "thumb_tiny.png"} + ] + ] + + """ + @spec process(Result.t(), Path.t(), version_list()) :: edit_script() + def process(analysis, file, versions) do + processor(analysis.mime_type).process(analysis, file, versions) + end + + @doc """ + Takes an analyzer result and file path and runs the appropriate processor's `post_process/2`, + performing long-running optimizations on the media source file. + + Returns an edit script to apply changes. Depending on the media type, this make take a long + time to execute. This may also be an empty list, if there are no changes to perform. + + ## Example + + iex> PhilomenaMedia.Processors.post_process(%Result{...}, "image.gif", [thumb_tiny: {50, 50}]) + [replace_original: "/tmp/briefly-5764/cyZSQnmL59XDRoPoaDxr.gif"] + + """ + @spec post_process(Result.t(), Path.t()) :: edit_script() + def post_process(analysis, file) do + processor(analysis.mime_type).post_process(analysis, file) + end + + @doc """ + Takes an analyzer result and file path and runs the appropriate processor's `intensities/2`, + returning the corner intensities. + + This allows for generating intensities for file types that are not directly supported by + `m:PhilomenaMedia.Intensities`, and should be the preferred function to call when intensities + are needed. + + ## Example + + iex> PhilomenaMedia.Processors.intensities(%Result{...}, "video.webm") + %Intensities{nw: 111.689148, ne: 116.228048, sw: 93.268433, se: 104.630064} + + """ + @spec intensities(Result.t(), Path.t()) :: Intensities.t() + def intensities(analysis, file) do + processor(analysis.mime_type).intensities(analysis, file) + end +end diff --git a/lib/philomena/processors/gif.ex b/lib/philomena_media/processors/gif.ex similarity index 83% rename from lib/philomena/processors/gif.ex rename to lib/philomena_media/processors/gif.ex index 8b7557e5..6e185f9f 100644 --- a/lib/philomena/processors/gif.ex +++ b/lib/philomena_media/processors/gif.ex @@ -1,12 +1,21 @@ -defmodule Philomena.Processors.Gif do - alias Philomena.Intensities +defmodule PhilomenaMedia.Processors.Gif do + @moduledoc false + alias PhilomenaMedia.Intensities + alias PhilomenaMedia.Analyzers.Result + alias PhilomenaMedia.Processors.Processor + alias PhilomenaMedia.Processors + + @behaviour Processor + + @spec versions(Processors.version_list()) :: [Processors.version_filename()] def versions(sizes) do sizes |> Enum.map(fn {name, _} -> "#{name}.gif" end) |> Kernel.++(["full.webm", "full.mp4", "rendered.png"]) end + @spec process(Result.t(), Path.t(), Processors.version_list()) :: Processors.edit_script() def process(analysis, file, versions) do duration = analysis.duration preview = preview(duration, file) @@ -17,16 +26,18 @@ defmodule Philomena.Processors.Gif do scaled = Enum.flat_map(versions, &scale(palette, file, &1)) videos = generate_videos(file) - %{ + [ intensities: intensities, thumbnails: scaled ++ videos ++ [{:copy, preview, "rendered.png"}] - } + ] end + @spec post_process(Result.t(), Path.t()) :: Processors.edit_script() def post_process(_analysis, file) do - %{replace_original: optimize(file)} + [replace_original: optimize(file)] end + @spec intensities(Result.t(), Path.t()) :: Intensities.t() def intensities(analysis, file) do {:ok, intensities} = Intensities.file(preview(analysis.duration, file)) intensities diff --git a/lib/philomena/processors/jpeg.ex b/lib/philomena_media/processors/jpeg.ex similarity index 79% rename from lib/philomena/processors/jpeg.ex rename to lib/philomena_media/processors/jpeg.ex index 24cf65e1..6e9f728e 100644 --- a/lib/philomena/processors/jpeg.ex +++ b/lib/philomena_media/processors/jpeg.ex @@ -1,10 +1,19 @@ -defmodule Philomena.Processors.Jpeg do - alias Philomena.Intensities +defmodule PhilomenaMedia.Processors.Jpeg do + @moduledoc false + alias PhilomenaMedia.Intensities + alias PhilomenaMedia.Analyzers.Result + alias PhilomenaMedia.Processors.Processor + alias PhilomenaMedia.Processors + + @behaviour Processor + + @spec versions(Processors.version_list()) :: [Processors.version_filename()] def versions(sizes) do Enum.map(sizes, fn {name, _} -> "#{name}.jpg" end) end + @spec process(Result.t(), Path.t(), Processors.version_list()) :: Processors.edit_script() def process(_analysis, file, versions) do stripped = optimize(strip(file)) @@ -12,15 +21,17 @@ defmodule Philomena.Processors.Jpeg do scaled = Enum.flat_map(versions, &scale(stripped, &1)) - %{ + [ replace_original: stripped, intensities: intensities, thumbnails: scaled - } + ] end - def post_process(_analysis, _file), do: %{} + @spec post_process(Result.t(), Path.t()) :: Processors.edit_script() + def post_process(_analysis, _file), do: [] + @spec intensities(Result.t(), Path.t()) :: Intensities.t() def intensities(_analysis, file) do {:ok, intensities} = Intensities.file(file) intensities diff --git a/lib/philomena/processors/png.ex b/lib/philomena_media/processors/png.ex similarity index 74% rename from lib/philomena/processors/png.ex rename to lib/philomena_media/processors/png.ex index 373ede0d..0fc4c50d 100644 --- a/lib/philomena/processors/png.ex +++ b/lib/philomena_media/processors/png.ex @@ -1,10 +1,19 @@ -defmodule Philomena.Processors.Png do - alias Philomena.Intensities +defmodule PhilomenaMedia.Processors.Png do + @moduledoc false + alias PhilomenaMedia.Intensities + alias PhilomenaMedia.Analyzers.Result + alias PhilomenaMedia.Processors.Processor + alias PhilomenaMedia.Processors + + @behaviour Processor + + @spec versions(Processors.version_list()) :: [Processors.version_filename()] def versions(sizes) do Enum.map(sizes, fn {name, _} -> "#{name}.png" end) end + @spec process(Result.t(), Path.t(), Processors.version_list()) :: Processors.edit_script() def process(analysis, file, versions) do animated? = analysis.animated? @@ -12,21 +21,23 @@ defmodule Philomena.Processors.Png do scaled = Enum.flat_map(versions, &scale(file, animated?, &1)) - %{ + [ intensities: intensities, thumbnails: scaled - } + ] end + @spec post_process(Result.t(), Path.t()) :: Processors.edit_script() def post_process(analysis, file) do if analysis.animated? do # libpng has trouble with animations, so skip optimization - %{} + [] else - %{replace_original: optimize(file)} + [replace_original: optimize(file)] end end + @spec intensities(Result.t(), Path.t()) :: Intensities.t() def intensities(_analysis, file) do {:ok, intensities} = Intensities.file(file) intensities diff --git a/lib/philomena_media/processors/processor.ex b/lib/philomena_media/processors/processor.ex new file mode 100644 index 00000000..2c3acc0b --- /dev/null +++ b/lib/philomena_media/processors/processor.ex @@ -0,0 +1,21 @@ +defmodule PhilomenaMedia.Processors.Processor do + @moduledoc false + + alias PhilomenaMedia.Analyzers.Result + alias PhilomenaMedia.Processors + alias PhilomenaMedia.Intensities + + # Generate a list of version filenames for the given version list. + @callback versions(Processors.version_list()) :: [Processors.version_filename()] + + # Process the media at the given path against the given version list, and return an + # edit script with the resulting files + @callback process(Result.t(), Path.t(), Processors.version_list()) :: Processors.edit_script() + + # Perform post-processing optimization tasks on the file, to reduce its size + # and strip non-essential metadata + @callback post_process(Result.t(), Path.t()) :: Processors.edit_script() + + # Generate corner intensities for the given path + @callback intensities(Result.t(), Path.t()) :: Intensities.t() +end diff --git a/lib/philomena/processors/svg.ex b/lib/philomena_media/processors/svg.ex similarity index 66% rename from lib/philomena/processors/svg.ex rename to lib/philomena_media/processors/svg.ex index 7f45b893..aaa3dd5c 100644 --- a/lib/philomena/processors/svg.ex +++ b/lib/philomena_media/processors/svg.ex @@ -1,12 +1,21 @@ -defmodule Philomena.Processors.Svg do - alias Philomena.Intensities +defmodule PhilomenaMedia.Processors.Svg do + @moduledoc false + alias PhilomenaMedia.Intensities + alias PhilomenaMedia.Analyzers.Result + alias PhilomenaMedia.Processors.Processor + alias PhilomenaMedia.Processors + + @behaviour Processor + + @spec versions(Processors.version_list()) :: [Processors.version_filename()] def versions(sizes) do sizes |> Enum.map(fn {name, _} -> "#{name}.png" end) |> Kernel.++(["rendered.png", "full.png"]) end + @spec process(Result.t(), Path.t(), Processors.version_list()) :: Processors.edit_script() def process(_analysis, file, versions) do preview = preview(file) @@ -15,14 +24,16 @@ defmodule Philomena.Processors.Svg do scaled = Enum.flat_map(versions, &scale(preview, &1)) full = [{:copy, preview, "full.png"}] - %{ + [ intensities: intensities, thumbnails: scaled ++ full ++ [{:copy, preview, "rendered.png"}] - } + ] end - def post_process(_analysis, _file), do: %{} + @spec post_process(Result.t(), Path.t()) :: Processors.edit_script() + def post_process(_analysis, _file), do: [] + @spec intensities(Result.t(), Path.t()) :: Intensities.t() def intensities(_analysis, file) do {:ok, intensities} = Intensities.file(preview(file)) intensities diff --git a/lib/philomena/processors/webm.ex b/lib/philomena_media/processors/webm.ex similarity index 90% rename from lib/philomena/processors/webm.ex rename to lib/philomena_media/processors/webm.ex index 8459ef8b..c86e1969 100644 --- a/lib/philomena/processors/webm.ex +++ b/lib/philomena_media/processors/webm.ex @@ -1,7 +1,15 @@ -defmodule Philomena.Processors.Webm do - alias Philomena.Intensities +defmodule PhilomenaMedia.Processors.Webm do + @moduledoc false + + alias PhilomenaMedia.Intensities + alias PhilomenaMedia.Analyzers.Result + alias PhilomenaMedia.Processors.Processor + alias PhilomenaMedia.Processors import Bitwise + @behaviour Processor + + @spec versions(Processors.version_list()) :: [Processors.version_filename()] def versions(sizes) do webm_versions = Enum.map(sizes, fn {name, _} -> "#{name}.webm" end) mp4_versions = Enum.map(sizes, fn {name, _} -> "#{name}.mp4" end) @@ -14,6 +22,7 @@ defmodule Philomena.Processors.Webm do ["full.mp4", "rendered.png"] ++ webm_versions ++ mp4_versions ++ gif_versions end + @spec process(Result.t(), Path.t(), Processors.version_list()) :: Processors.edit_script() def process(analysis, file, versions) do dimensions = analysis.dimensions duration = analysis.duration @@ -27,15 +36,17 @@ defmodule Philomena.Processors.Webm do scaled = Enum.flat_map(versions, &scale(stripped, palette, duration, dimensions, &1)) mp4 = [{:copy, mp4, "full.mp4"}] - %{ + [ replace_original: stripped, intensities: intensities, thumbnails: scaled ++ mp4 ++ [{:copy, preview, "rendered.png"}] - } + ] end - def post_process(_analysis, _file), do: %{} + @spec post_process(Result.t(), Path.t()) :: Processors.edit_script() + def post_process(_analysis, _file), do: [] + @spec intensities(Result.t(), Path.t()) :: Intensities.t() def intensities(analysis, file) do {:ok, intensities} = Intensities.file(preview(analysis.duration, file)) intensities diff --git a/lib/philomena/sha512.ex b/lib/philomena_media/sha512.ex similarity index 63% rename from lib/philomena/sha512.ex rename to lib/philomena_media/sha512.ex index 03c9645e..ba12cfed 100644 --- a/lib/philomena/sha512.ex +++ b/lib/philomena_media/sha512.ex @@ -1,6 +1,21 @@ -defmodule Philomena.Sha512 do +defmodule PhilomenaMedia.Sha512 do + @moduledoc """ + Streaming SHA-512 processor. + """ + @chunk_size 10_485_760 + @doc """ + Generate the SHA2-512 hash of the file at the given path as a string. + + The file is processed in 10MiB chunks. + + ## Example + + iex> Sha512.file("image.png") + "97fd5243cd39e225f1478097acae71fbbff7f3027b24f0e6a8e06a0d7d3e6861cd05691d7470c76e7dfc4eb30459a906918d5ba0d144184fff02b8e34bd9ecf8" + + """ @spec file(Path.t()) :: String.t() def file(path) do hash_ref = :crypto.hash_init(:sha512) diff --git a/lib/philomena_media/uploader.ex b/lib/philomena_media/uploader.ex new file mode 100644 index 00000000..3df61945 --- /dev/null +++ b/lib/philomena_media/uploader.ex @@ -0,0 +1,360 @@ +defmodule PhilomenaMedia.Uploader do + @moduledoc """ + Upload and processing callback logic for media files. + + To use the uploader, the target schema must be modified to add at least the + following fields, assuming the name of the field to write to the database is `foo`: + + field :foo, :string + field :uploaded_foo, :string, virtual: true + field :removed_foo, :string, virtual: true + + The schema should also define a changeset function which casts the file parameters. This may be + the default changeset function, or a function specialized to accept only the file parameters. A + minimal schema must cast at least the following to successfully upload and replace files: + + def foo_changeset(schema, attrs) do + cast(schema, attrs, [:foo, :uploaded_foo, :removed_foo]) + end + + Additional fields may be added to perform validations. For example, specifying a field name + `foo_mime_type` allows the creation of a MIME type filter in the changeset: + + def foo_changeset(schema, attrs) do + schema + |> cast(attrs, [:foo, :foo_mime_type, :uploaded_foo, :removed_foo]) + |> validate_required([:foo, :foo_mime_type]) + |> validate_inclusion(:foo_mime_type, ["image/svg+xml"]) + end + + See `analyze_upload/4` for more information about what fields may be validated in this + fashion. + + Generally, you should expect to create a `Schemas.Uploader` module, which defines functions as + follows, pointing to `m:PhilomenaMedia.Uploader`. Assuming the target field name is `"foo"`, then: + + defmodule Philomena.Schemas.Uploader do + alias Philomena.Schemas.Schema + alias PhilomenaMedia.Uploader + + @field_name "foo" + + def analyze_upload(schema, params) do + Uploader.analyze_upload(schema, @field_name, params[@field_name], &Schema.foo_changeset/2) + end + + def persist_upload(schema) do + Uploader.persist_upload(schema, schema_file_root(), @field_name) + end + + def unpersist_old_upload(schema) do + Uploader.unpersist_old_upload(schema, schema_file_root(), @field_name) + end + + defp schema_file_root do + Application.get_env(:philomena, :schema_file_root) + end + end + + A typical context usage may then look like: + + alias Philomena.Schemas.Schema + alias Philomena.Schemas.Uploader + + @spec create_schema(map()) :: {:ok, Schema.t()} | {:error, Ecto.Changeset.t()} + def create_schema(attrs) do + %Schema{} + |> Uploader.analyze_upload(attrs) + |> Repo.insert() + |> case do + {:ok, schema} -> + Uploader.persist_upload(schema) + + {:ok, schema} + + error -> + error + end + end + + @spec update_schema(Schema.t(), map()) :: {:ok, Schema.t()} | {:error, Ecto.Changeset.t()} + def update_schema(%Schema{} = schema, attrs) do + schema + |> Uploader.analyze_upload(attrs) + |> Repo.update() + |> case do + {:ok, schema} -> + Uploader.persist_upload(schema) + Uploader.unpersist_old_upload(schema) + + {:ok, schema} + + error -> + error + end + end + + This forwards to the core `m:PhilomenaMedia.Uploader` logic with information about the file root. + + The file root is the location at which files of the given schema type are located under + the storage path. For example, the file root for the Adverts schema may be + `/srv/philomena/priv/s3/philomena/adverts` in development with the file backend, + and just `adverts` in production with the S3 backend. + + It is not recommended to perform persist or unpersist operations in the scope of an `m:Ecto.Multi`, + as they may block indefinitely. + """ + + alias PhilomenaMedia.Analyzers + alias PhilomenaMedia.Filename + alias PhilomenaMedia.Objects + alias PhilomenaMedia.Sha512 + import Ecto.Changeset + + @type schema :: struct() + @type schema_or_changeset :: struct() | Ecto.Changeset.t() + + @type field_name :: String.t() + @type file_root :: String.t() + + @doc """ + Performs analysis of the specified `m:Plug.Upload`, and invokes a changeset callback on the schema + or changeset passed in. + + The file name which will be written to is set by the assignment to the schema's `field_name`, and + the below attributes are prefixed by the `field_name`. + + Assuming the file is successfully parsed, this will attempt to cast the following + attributes into the specified changeset function: + * `name` (String) - the name of the file + * `width` (integer) - the width of the file + * `height` (integer) - the height of the file + * `size` (integer) - the size of the file, in bytes + * `format` (String) - the file extension, one of `~w(gif jpg png svg webm)`, determined by reading the file + * `mime_type` (String) - the file's sniffed MIME type, determined by reading the file + * `duration` (float) - the duration of the media file + * `aspect_ratio` (float) - width divided by height. + * `orig_sha512_hash` (String) - the SHA-512 hash of the file + * `sha512_hash` (String) - the SHA-512 hash of the file + * `is_animated` (boolean) - whether the file contains animation + + You may design your changeset callback to accept any of these. Here is an example which accepts + all of them: + + def foo_changeset(schema, attrs) + cast(schema, attrs, [ + :foo, + :foo_name, + :foo_width, + :foo_height, + :foo_size, + :foo_format, + :foo_mime_type, + :foo_duration, + :foo_aspect_ratio, + :foo_orig_sha512_hash, + :foo_sha512_hash, + :foo_is_animated, + :uploaded_foo, + :removed_foo + ]) + end + + Attributes are prefixed, so assuming a `field_name` of `"foo"`, this would result in + the changeset function receiving attributes `"foo_name"`, `"foo_width"`, ... etc. + + Validations on the uploaded media are also possible in the changeset callback. For example, + `m:Philomena.Adverts.Advert` performs validations on MIME type and width of its field, named + `image`: + + def image_changeset(advert, attrs) do + advert + |> cast(attrs, [ + :image, + :image_mime_type, + :image_size, + :image_width, + :image_height, + :uploaded_image, + :removed_image + ]) + |> validate_required([:image]) + |> validate_inclusion(:image_mime_type, ["image/png", "image/jpeg", "image/gif"]) + |> validate_inclusion(:image_width, 699..729) + end + + The key (location to write the persisted file) is passed with the `field_name` attribute into the + changeset callback. The key is calculated using the current date, a UUID, and the computed + extension. A file uploaded may therefore be given a key such as + `2024/1/1/0bce8eea-17e0-11ef-b7d4-0242ac120006.png`. See `PhilomenaMedia.Filename.build/1` for + the actual construction. + + This function does not persist an upload to storage. + + See the module documentation for a complete example. + + ## Example + + @spec analyze_upload(Uploader.schema_or_changeset(), map()) :: Ecto.Changeset.t() + def analyze_upload(schema, params) do + Uploader.analyze_upload(schema, "foo", params["foo"], &Schema.foo_changeset/2) + end + + """ + @spec analyze_upload( + schema_or_changeset(), + field_name(), + Plug.Upload.t(), + (schema_or_changeset(), map() -> Ecto.Changeset.t()) + ) :: Ecto.Changeset.t() + def analyze_upload(schema_or_changeset, field_name, upload_parameter, changeset_fn) do + with {:ok, analysis} <- Analyzers.analyze(upload_parameter), + analysis <- extra_attributes(analysis, upload_parameter) do + removed = + schema_or_changeset + |> change() + |> get_field(field(field_name)) + + attributes = + %{ + "name" => analysis.name, + "width" => analysis.width, + "height" => analysis.height, + "size" => analysis.size, + "format" => analysis.extension, + "mime_type" => analysis.mime_type, + "duration" => analysis.duration, + "aspect_ratio" => analysis.aspect_ratio, + "orig_sha512_hash" => analysis.sha512, + "sha512_hash" => analysis.sha512, + "is_animated" => analysis.animated? + } + |> prefix_attributes(field_name) + |> Map.put(field_name, analysis.new_name) + |> Map.put(upload_key(field_name), upload_parameter.path) + |> Map.put(remove_key(field_name), removed) + + changeset_fn.(schema_or_changeset, attributes) + else + {:unsupported_mime, mime} -> + attributes = prefix_attributes(%{"mime_type" => mime}, field_name) + changeset_fn.(schema_or_changeset, attributes) + + _error -> + changeset_fn.(schema_or_changeset, %{}) + end + end + + @doc """ + Writes the file to permanent storage. This should be the second-to-last step + before completing a file operation. + + The key (location to write the persisted file) is fetched from the schema by `field_name`. + This is then prefixed with the `file_root` specified by the caller. Finally, the file is + written to storage. + + See the module documentation for a complete example. + + ## Example + + @spec persist_upload(Schema.t()) :: :ok + def persist_upload(schema) do + Uploader.persist_upload(schema, schema_file_root(), "foo") + end + + """ + @spec persist_upload(schema(), file_root(), field_name()) :: :ok + def persist_upload(schema, file_root, field_name) do + source = Map.get(schema, field(upload_key(field_name))) + dest = Map.get(schema, field(field_name)) + target = Path.join(file_root, dest) + + persist_file(target, source) + end + + @doc """ + Persist an arbitrary file to storage with the given key. + + > #### Warning {: .warning} + > + > This is exposed for schemas which do not store their files at at an offset from a file root, + > to allow overriding the key. If you do not need to override the key, use + > `persist_upload/3` instead. + + The key (location to write the persisted file) and the file path to upload are passed through + to `PhilomenaMedia.Objects.upload/2` without modification. See the definition of that function for + additional details. + + ## Example + + key = "2024/1/1/5/full.png" + Uploader.persist_file(key, file_path) + + """ + @spec persist_file(Objects.key(), Path.t()) :: :ok + def persist_file(key, file_path) do + Objects.upload(key, file_path) + end + + @doc """ + Removes the old file from permanent storage. This should be the last step in + completing a file operation. + + The key (location to write the persisted file) is fetched from the schema by `field_name`. + This is then prefixed with the `file_root` specified by the caller. Finally, the file is + purged from storage. + + See the module documentation for a complete example. + + ## Example + + @spec unpersist_old_upload(Schema.t()) :: :ok + def unpersist_old_upload(schema) do + Uploader.unpersist_old_upload(schema, schema_file_root(), "foo") + end + + """ + @spec unpersist_old_upload(schema(), file_root(), field_name()) :: :ok + def unpersist_old_upload(schema, file_root, field_name) do + schema + |> Map.get(field(remove_key(field_name))) + |> try_remove(file_root) + end + + defp extra_attributes(analysis, %Plug.Upload{path: path, filename: filename}) do + {width, height} = analysis.dimensions + aspect_ratio = aspect_ratio(width, height) + + stat = File.stat!(path) + sha512 = Sha512.file(path) + new_name = Filename.build(analysis.extension) + + analysis + |> Map.put(:size, stat.size) + |> Map.put(:name, filename) + |> Map.put(:width, width) + |> Map.put(:height, height) + |> Map.put(:sha512, sha512) + |> Map.put(:new_name, new_name) + |> Map.put(:aspect_ratio, aspect_ratio) + end + + defp aspect_ratio(_, 0), do: 0.0 + defp aspect_ratio(w, h), do: w / h + + defp try_remove("", _file_root), do: :ok + defp try_remove(nil, _file_root), do: :ok + + defp try_remove(file, file_root) do + Objects.delete(Path.join(file_root, file)) + end + + defp prefix_attributes(map, prefix), + do: Map.new(map, fn {key, value} -> {"#{prefix}_#{key}", value} end) + + defp upload_key(field_name), do: "uploaded_#{field_name}" + + defp remove_key(field_name), do: "removed_#{field_name}" + + defp field(field_name), do: String.to_existing_atom(field_name) +end diff --git a/lib/philomena_web/image_reverse.ex b/lib/philomena_web/image_reverse.ex index 4fa5f459..161ebad3 100644 --- a/lib/philomena_web/image_reverse.ex +++ b/lib/philomena_web/image_reverse.ex @@ -1,6 +1,6 @@ defmodule PhilomenaWeb.ImageReverse do - alias Philomena.Analyzers - alias Philomena.Processors + alias PhilomenaMedia.Analyzers + alias PhilomenaMedia.Processors alias Philomena.DuplicateReports alias Philomena.Repo import Ecto.Query