From 6004ca22bbbb10c2ae7d036abce9d8ddd8ed21b8 Mon Sep 17 00:00:00 2001 From: weeklies <80141759+weeklies@users.noreply.github.com> Date: Fri, 17 May 2024 17:18:51 +0100 Subject: [PATCH 001/181] AO3-5371 Add descriptive classes to external work and series blurbs (#4560) * Add descriptive classes to series and external work blurbs * Try to do i18n * AO3-5371 Add number delimiter * AO3-5371 Normalize * AO3-5371 Move localization to model * AO3-5371 Missed one * AO3-5371 Fix typo --- app/helpers/bookmarks_helper.rb | 2 +- app/views/external_works/_blurb.html.erb | 8 ++++---- app/views/external_works/_work_module.html.erb | 10 +++++----- app/views/series/_series_module.html.erb | 12 ++++++------ app/views/series/show.html.erb | 12 ++++++------ config/locales/models/en.yml | 12 ++++++++++-- 6 files changed, 32 insertions(+), 24 deletions(-) diff --git a/app/helpers/bookmarks_helper.rb b/app/helpers/bookmarks_helper.rb index b1d7be1e0f5..a9c09e3b2f4 100644 --- a/app/helpers/bookmarks_helper.rb +++ b/app/helpers/bookmarks_helper.rb @@ -31,7 +31,7 @@ def link_to_tag_bookmarks(tag) def link_to_bookmarkable_bookmarks(bookmarkable, link_text='') if link_text.blank? - link_text = Bookmark.count_visible_bookmarks(bookmarkable, current_user) + link_text = number_with_delimiter(Bookmark.count_visible_bookmarks(bookmarkable, current_user)) end path = case bookmarkable.class.name when "Work" diff --git a/app/views/external_works/_blurb.html.erb b/app/views/external_works/_blurb.html.erb index 1a85e33a4e6..e9b33ee4820 100644 --- a/app/views/external_works/_blurb.html.erb +++ b/app/views/external_works/_blurb.html.erb @@ -42,12 +42,12 @@
- <%= ts("This work isn't hosted on the Archive so this blurb might not be complete + <%= ts("This work isn't hosted on the Archive so this blurb might not be complete or accurate.") %>
@@ -49,12 +49,12 @@ <% end %> <% if Bookmark.count_visible_bookmarks(external_work) > 0 %> -<%= t(".blocked") %>
+ <% elsif logged_in_as_admin? %> ++ <%= t(".logged_as_admin") %> +
<% else %>- We're working hard to reply to everyone, and we'll respond to you as soon as we can. - Your communication is greatly valued, and it will be reviewed and - answered by our volunteer Support team. In the meantime, here is a copy of - the information you submitted through the Technical Support and Feedback - form: -
+<%= t(".introduction") %>
<%= style_quote("#{raw(strip_images(@summary))} #{raw(strip_images(@comment, keep_src: true))}") %> -- If you have additional questions or information, do not hesitate to send in - another ticket. -
+<%= t(".additional_ticket") %>
<%= t("mailer.general.closing.formal") %> <%= t(".translated_post.footnote_tags") %>
- <%= t(".moderation_forewarning") %>
+ <%# i18n-tasks-use
+ t("comments.commentable.permissions.moderated_commenting.notice.admin_post")
+ t("comments.commentable.permissions.moderated_commenting.notice.work") %>
+ <%= t("comments.commentable.permissions.moderated_commenting.notice.#{commentable.model_name.i18n_key}") %>
<%= ts('Please note that comments cannot be unapproved once you have reviewed them. After you delete any comments you do not wish to appear on your work, you can approve all that remain.') %> <%= t(".note.#{@commentable.model_name.i18n_key}") %> <%= ts("No unreviewed comments.") %> <%= t(".no_unreviewed") %> <%= t(".introduction") %>
+ We're working hard to reply to everyone, and we'll respond to you as soon as we can.
+ Your communication is greatly valued, and it will be reviewed and
+ answered by our volunteer Support team. In the meantime, here is a copy of
+ the information you submitted through the Technical Support and Feedback
+ form:
+ <%= t(".additional_ticket") %>
+ If you have additional questions or information, do not hesitate to send in
+ another ticket.
+
<%= t("mailer.general.closing.formal") %>
- <%= ts("This work isn't hosted on the Archive so this blurb might not be complete
+ <%= ts("This work isn't hosted on the Archive so this blurb might not be complete
or accurate.") %>
- <%= ts("This work isn't hosted on the Archive so this blurb might not be complete
+ <%= ts("This work isn't hosted on the Archive so this blurb might not be complete
or accurate.") %>
- We're working hard to reply to everyone, and we'll respond to you as soon as we can.
- Your communication is greatly valued, and it will be reviewed and
- answered by our volunteer Support team. In the meantime, here is a copy of
- the information you submitted through the Technical Support and Feedback
- form:
- <%= t(".introduction") %>
- If you have additional questions or information, do not hesitate to send in
- another ticket.
- <%= t(".additional_ticket") %>
<%= t("mailer.general.closing.formal") %>
- <%# i18n-tasks-use
- t("comments.commentable.permissions.moderated_commenting.notice.admin_post")
- t("comments.commentable.permissions.moderated_commenting.notice.work") %>
- <%= t("comments.commentable.permissions.moderated_commenting.notice.#{commentable.model_name.i18n_key}") %>
+ <% if commentable.is_a?(AdminPost) %>
+ <%= t("comments.commentable.permissions.moderated_commenting.notice.admin_post") %>
+ <% else %>
+ <%= t("comments.commentable.permissions.moderated_commenting.notice.work") %>
+ <% end %>
- <%= ts("Orphaning all of your works will")%>
- <%= ts("permanently")%>
- <%= ts("remove all identifying data from the following work(s), their chapters, associated series, and any feedback replies you may have left on them.") %>
- <%= t(".orphaning_works_message_html") %> <%= t(".orphaning_bylines_only_message_html") %>
<%= ts("Orphaning a work removes it from your account and re-attaches it to the specially created orphan_account. Please note that this is")%>
diff --git a/config/locales/views/en.yml b/config/locales/views/en.yml
index 406a1112496..ac8047ce282 100644
--- a/config/locales/views/en.yml
+++ b/config/locales/views/en.yml
@@ -723,6 +723,10 @@ en:
hide_content_for_others: hide their works, series, bookmarks, and comments from anyone else
intro: 'Muting a user will not:'
prevent_emails: prevent you from receiving comment or subscription emails from this user
+ orphans:
+ orphan_user:
+ orphaning_bylines_only_message_html: Orphaning will automatically remove your personal information from bylines only. It will not automatically remove your personal information from anywhere else in the work(s). Social media accounts, contact information, email addresses, names, and any other personal information posted in the title, summary, notes, tags, work body, or comment text will not be automatically removed. Comments posted by other users will also not be affected by Orphaning. If you want information removed from these places, you should edit or delete it prior to Orphaning. Once you Orphan the work(s), you will no longer be able to delete information in these places yourself.
+ orphaning_works_message_html: 'Orphaning will permanently remove your username and/or pseud from the bylines of: the following work(s), their chapters, associated series, and any comments you may have left on them while logged into this account.'
preferences:
index:
allow_collection_invitation: Allow others to invite my works to collections.
From 9d15b0349e7ec9135c13d3adbaccc8016f790e2e Mon Sep 17 00:00:00 2001
From: Bilka <%= ts("The Organization for Transformative Works (OTW) is a nonprofit organization, established by fans in 2007, to serve the interests of fans by providing access to and preserving the history of fanworks and fan culture in its myriad forms. We believe that fanworks are transformative and that transformative works are legitimate.") %> <%= ts("We are proactive and innovative in protecting and defending our work from commercial exploitation and legal challenge. We preserve our fannish economy, values, and creative expression by protecting and nurturing our fellow fans, our work, our commentary, our history, and our identity while providing the broadest possible access to fannish activity for all fans.") %> <%= ts("The Archive of Our Own offers a noncommercial and nonprofit central hosting place for fanworks using open-source archiving software.") %> <%= ts("Our other major projects include:") %>
+ <%= t(".general") %> <%= t(".details") %> <%= t(".ao3.html",
+ github_repository_link: link_to(t(".ao3.github_repository"), "https://github.com/otwcode/otwarchive"),
+ jira_project_link: link_to(t(".ao3.jira_project"), "https://otwarchive.atlassian.net/browse/AO3")) %> <%= t(".major_projects.title") %>
<%= ts("You can find out more about the OTW and its projects at its website, %{transformative_works}, and learn about how your financial support is vital to the continuation and expansion of the OTW's work on its %{faq}. If you have a media or research question, please contact the %{communications_team}.", :transformative_works => link_to(ts("transformativeworks.org"), "http://transformativeworks.org"), :faq => link_to(ts("FAQ page"), "http://transformativeworks.org/faq"), :communications_team => link_to(ts("Communications team"), "http://transformativeworks.org/contact_us/")).html_safe %> <%= t(".more_info.html",
+ transformative_works_link: link_to(t(".more_info.transformative_works"), "https://www.transformativeworks.org"),
+ faq_page_link: link_to(t(".more_info.faq_page"), "https://www.transformativeworks.org/faq"),
+ communications_team_link: link_to(t(".more_info.communications_team"), "https://www.transformativeworks.org/contact_us/")) %> <%= t(".time.details_html",
- otw_link: link_to(t(".time.otw"), "http://www.transformativeworks.org"),
- projects_link: link_to(t(".time.projects"), "http://www.transformativeworks.org/our-projects"),
- volunteer_link: link_to(t(".time.volunteer"), "http://www.transformativeworks.org/volunteer")) %> <%= t(".time.info_html",
+ otw_link: link_to(t(".time.otw"), "https://www.transformativeworks.org"),
+ projects_link: link_to(t(".time.projects"), "https://www.transformativeworks.org/our-projects")) %> <%= t(".time.contribute_html",
+ github_repository_link: link_to(t(".time.github_repository"), "https://github.com/otwcode/otwarchive"),
+ jira_project_link: link_to(t(".time.jira_project"), "https://otwarchive.atlassian.net/browse/AO3"),
+ volunteer_listings_link: link_to(t(".time.volunteer_listings"), "https://www.transformativeworks.org/volunteer"),
+ news_by_email_link: link_to(t(".time.news_by_email"), "https://www.transformativeworks.org/you-can-now-subscribe-to-otw-news-by-email")) %> <%= t(".money.details_html",
diff --git a/config/locales/views/en.yml b/config/locales/views/en.yml
index ac8047ce282..3c71d374377 100644
--- a/config/locales/views/en.yml
+++ b/config/locales/views/en.yml
@@ -569,6 +569,33 @@ en:
tumblr: ao3org Tumblr
twitter: "@AO3_Status Twitter feed"
home:
+ about:
+ ao3:
+ github_repository: GitHub repository
+ html: The Archive of Our Own offers a noncommercial and nonprofit central hosting place for fanworks using open-source archiving software. We welcome contributions to our %{github_repository_link}, and a list of open tasks is available on our %{jira_project_link}.
+ jira_project: Jira project
+ details: We are proactive and innovative in protecting and defending our work from commercial exploitation and legal challenge. We preserve our fannish economy, values, and creative expression by protecting and nurturing our fellow fans, our work, our commentary, our history, and our identity while providing the broadest possible access to fannish activity for all fans.
+ general: The Organization for Transformative Works (OTW) is a nonprofit organization, established by fans in 2007, to serve the interests of fans by providing access to and preserving the history of fanworks and fan culture in its myriad forms. We believe that fanworks are transformative and that transformative works are legitimate.
+ heading:
+ html: About the %{otw}
+ otw: OTW
+ otw_long: Organization for Transformative Works
+ major_projects:
+ fanlore: Fanlore
+ fanlore_details_html: "%{fanlore_link}, a fandom wiki devoted to preserving the history of transformative fanworks and the fandoms from which they have arisen."
+ legal_advocacy: Legal Advocacy
+ legal_details_html: "%{legal_advocacy_link} committed to protecting and defending fanworks from commercial exploitation and legal challenge."
+ open_doors: Open Doors
+ open_doors_details_html: "%{open_doors_link}, which offers shelter to at-risk fannish projects."
+ title: 'Our other major projects include:'
+ twc: Transformative Works and Cultures
+ twc_details_html: "%{twc_link}, a peer-reviewed academic journal that seeks to promote scholarship on fanworks and practices."
+ more_info:
+ communications_team: Communications team
+ faq_page: FAQ page
+ html: You can find out more about the OTW and its projects at its website, %{transformative_works_link}, and learn about how your financial support is vital to the continuation and expansion of the OTW's work on its %{faq_page_link}. If you have a media or research question, please contact the %{communications_team_link}.
+ transformative_works: transformativeworks.org
+ page_title: About the OTW
donate:
general:
text: There are two main ways to support the AO3 - donating your time or money.
@@ -579,11 +606,15 @@ en:
title: Donating Financially
page_title: Donate or Volunteer
time:
- details_html: The %{otw_link} is the parent organization of the Archive of Our Own. We are often looking for volunteers to contribute to %{projects_link}. If you're interested in volunteering specifically to help the Archive of Our Own, the roles to look out for include tag wranglers, testers, coders, Support staff and Abuse staff. We encourage you to browse through the %{volunteer_link} and apply for any roles which match your qualifications and interests.
+ contribute_html: We also welcome community contributions to %{github_repository_link} for open tasks in our %{jira_project_link}. We also encourage you to browse through our %{volunteer_listings_link}, sign up to receive all our %{news_by_email_link} which includes our calls for volunteers, and apply for any volunteer roles that match your qualifications and interests.
+ github_repository: our GitHub repository
+ info_html: The %{otw_link} is the parent organization of the Archive of Our Own (AO3). We are often looking for volunteers to contribute to %{projects_link}. If you are interested in volunteering specifically to help the Archive of Our Own, the committees to look out for include Accessibility, Design, and Technology (AD&T); AO3 Documentation; Policy & Abuse; Support; Tag Wrangling; and Translation.
+ jira_project: Jira project
+ news_by_email: news by email
otw: Organization for Transformative Works
projects: our projects
title: Donating Your Time
- volunteer: available listings
+ volunteer_listings: volunteer position listings
fandoms:
all_fandoms: All Fandoms
index:
diff --git a/features/other_a/homepage.feature b/features/other_a/homepage.feature
index 418a936d11b..e2376466af3 100644
--- a/features/other_a/homepage.feature
+++ b/features/other_a/homepage.feature
@@ -25,3 +25,10 @@ Feature: Various things on the homepage
Then I should see "There are two main ways to support the AO3 - donating your time or money"
And I should see the page title "Donate or Volunteer"
And I should see a link "donation to the OTW" to "https://donate.transformativeworks.org/otwgive"
+
+ Scenario: About
+
+ Given I am on the about page
+ Then I should see the page title "About the OTW"
+ And I should see a link "GitHub repository" to "https://github.com/otwcode/otwarchive"
+ And I should see a link "Jira project" to "https://otwarchive.atlassian.net/browse/AO3"
From c90f591062f9870473af4917b6c0726e1ae8c970 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 15 Jul 2024 07:37:55 -0700
Subject: [PATCH 062/181] AO3-6763 Bump reviewdog/action-rubocop from 2.16.0 to
2.18.0 (#4873)
Bumps [reviewdog/action-rubocop](https://github.com/reviewdog/action-rubocop) from 2.16.0 to 2.18.0.
- [Release notes](https://github.com/reviewdog/action-rubocop/releases)
- [Commits](https://github.com/reviewdog/action-rubocop/compare/4e3af4bbf94fe89f42f1f088be89f2918f21cc5e...7ef50b200dba9fb54c97392337ac7e82d692c4bd)
---
updated-dependencies:
- dependency-name: reviewdog/action-rubocop
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot]
<%# i18n-tasks-use t('user_mailer.creatorship_notification.intro_chapter')
- i18n-tasks-use t('user_mailer.creatorship_notification.intro_series')
- i18n-tasks-use t('user_mailer.creatorship_notification.intro_work')-%>
+ i18n-tasks-use t('user_mailer.creatorship_notification.intro_series')-%>
<%= t(".intro_#{creation_type}", adding_user: @adding_user.login, pseud: @creatorship.pseud.name) %>
<%# i18n-tasks-use t('user_mailer.creatorship_notification.html.remove_chapter')
i18n-tasks-use t('user_mailer.creatorship_notification.html.remove_series')
- i18n-tasks-use t('user_mailer.creatorship_notification.html.remove_work')
i18n-tasks-use t('user_mailer.creatorship_notification.html.edit_chapter')
- i18n-tasks-use t('user_mailer.creatorship_notification.html.edit_series')
- i18n-tasks-use t('user_mailer.creatorship_notification.html.edit_work')-%>
+ i18n-tasks-use t('user_mailer.creatorship_notification.html.edit_series')-%>
<%= t(".html.remove_#{creation_type}", "edit_#{creation_type}_link": style_link(t(".html.edit_#{creation_type}"), edit_polymorphic_url(@creation))).html_safe %>
Galera Cluster for clustered MySQL. GitHub for collaborative programming. HAProxy for load balancing. Hound for style guidance. Hound and reviewdog for style guidance. Jira for our issue tracking. NGINX for our front end. Memcached for caching. RSpec for unit tests. Ruby as our language. RubyMine for our integrated development environment. Sentry for APM/application monitoring. Slack for communications. Vagrant for our development environment. <%= icon_display(@wrangler) %> <%= ts("Search for an API token by name") %> <%= t(".search_by_name") %> <%= submit_tag ts("Find") %> <%= submit_tag t(".actions.find") %> <%= t("mailer.general.greeting.informal.addressed", name: style_bold(t("mailer.general.greeting.tag_wrangler_supervisors"))).html_safe %> <%= t(".name_changed.html", old_username: style_bold(@old_username), new_username: style_bold(@new_username)) %>
+ <%= t("mailer.general.closing.informal") %>
- <%= ts("Are you sure you want to delete all the works and comments created by this user,
- along with their %{bookmarks} bookmarks, %{series} series, and %{collections} collections? This cannot be undone.",
- bookmarks: @bookmarks.size, series: @series.size, collections: @collections.size).html_safe %>
+ <%= t(".caution_html", bookmarks: @bookmarks.size, series: @series.size, collections: @collections.size) %>
- <%= submit_tag ts("Yes, Delete All Spammer Creations"),
- data: { confirm: ts("Are you sure? Remember this will destroy ALL these objects!") } %>
+ <%= submit_tag t(".submit"), data: { confirm: t(".confirm") } %>
<%= t(".no_creations") %> Neener <%= t("mailer.general.greeting.formal", name: style_bold(@resource.login)).html_safe %> <%= t("mailer.general.greeting.formal_html", name: style_bold(@resource.login)) %> <%= t(".intro") %> <%= style_link t(".link_title_html"), edit_admin_password_url(reset_password_token: @token) %> <%= t(".expiration", count: ArchiveConfig.DAYS_UNTIL_ADMIN_RESET_PASSWORD_LINK_EXPIRES) %> <%= t("mailer.general.greeting.informal.addressed", name: style_bold(@admin.login)).html_safe %> <%= t("mailer.general.greeting.informal.addressed_html", name: style_bold(@admin.login)) %> <%= t(".created") %> <%= style_work_metadata_label(t(".username")) %><%= @admin.login %> <%= style_work_metadata_label(t(".url")) %><%= style_link(new_admin_session_url, new_admin_session_url) %> <%= t("mailer.general.greeting.informal.addressed", name: style_bold(t("mailer.general.greeting.tag_wrangler_supervisors"))).html_safe %> <%= t("mailer.general.greeting.informal.addressed_html", name: style_bold(t("mailer.general.greeting.tag_wrangler_supervisors"))) %> <%= t(".name_changed.html", old_username: style_bold(@old_username), new_username: style_bold(@new_username)) %>
<% if @username.present? %>
- <%= t("mailer.general.greeting.informal.addressed",
- name: style_bold(@username)).html_safe %> <%= t("mailer.general.greeting.formal", name: style_bold(@user.login)).html_safe %> <%= t("mailer.general.greeting.formal_html", name: style_bold(@user.login)) %> <%= t('.deleted.html', title: style_creation_title(@work.title)) %> <%= t("mailer.general.greeting.formal", name: style_bold(@user.login)).html_safe %> <%= t("mailer.general.greeting.formal_html", name: style_bold(@user.login)) %> <%= t(".html.hidden", title: style_creation_link(@work.title, @work)).html_safe %> <%= t("mailer.general.greeting.formal", name: style_bold(@user.login)).html_safe %> <%= t("mailer.general.greeting.formal_html", name: style_bold(@user.login)) %> Your work <%= style_creation_link(@work.title, @work) %> has been flagged by our automated system as spam and hidden until it can be reviewed by our Policy & Abuse team. While the work is hidden it can only be accessed by you and AO3 site admins. <%= t("mailer.general.greeting.formal", name: style_bold(@user.login)).html_safe %> <%= t("mailer.general.greeting.formal_html", name: style_bold(@user.login)) %> <%= t(".changed_status.#{@status}.html",
collection_link: style_link(@collection.title, collection_url(@collection)),
diff --git a/app/views/user_mailer/anonymous_or_unrevealed_notification.text.erb b/app/views/user_mailer/anonymous_or_unrevealed_notification.text.erb
index e01dff7c98f..d4e50809e9c 100644
--- a/app/views/user_mailer/anonymous_or_unrevealed_notification.text.erb
+++ b/app/views/user_mailer/anonymous_or_unrevealed_notification.text.erb
@@ -1,5 +1,5 @@
<% content_for :message do %>
-<%= t("mailer.general.greeting.formal", name: @user.login) %>
+<%= t("mailer.general.greeting.formal_html", name: @user.login) %>
<%= t(".changed_status.#{@status}.text",
collection_title: @collection.title,
diff --git a/app/views/user_mailer/archivist_added_to_collection_notification.html.erb b/app/views/user_mailer/archivist_added_to_collection_notification.html.erb
index a79bca7ae63..ee22533e936 100644
--- a/app/views/user_mailer/archivist_added_to_collection_notification.html.erb
+++ b/app/views/user_mailer/archivist_added_to_collection_notification.html.erb
@@ -1,5 +1,5 @@
<% content_for :message do %>
- <%= t("mailer.general.greeting.formal", name: style_bold(@user.login)).html_safe %> <%= t("mailer.general.greeting.formal_html", name: style_bold(@user.login)) %>
<%= t(".work_added.html",
diff --git a/app/views/user_mailer/archivist_added_to_collection_notification.text.erb b/app/views/user_mailer/archivist_added_to_collection_notification.text.erb
index d42bf05ca13..58c9a5b2738 100644
--- a/app/views/user_mailer/archivist_added_to_collection_notification.text.erb
+++ b/app/views/user_mailer/archivist_added_to_collection_notification.text.erb
@@ -1,5 +1,5 @@
<% content_for :message do %>
-<%= t("mailer.general.greeting.formal", name: @user.login) %>
+<%= t("mailer.general.greeting.formal_html", name: @user.login) %>
<%= t(".work_added.text",
collection_title: @collection.title,
diff --git a/app/views/user_mailer/delete_work_notification.html.erb b/app/views/user_mailer/delete_work_notification.html.erb
index 4a282752790..1004535e31a 100644
--- a/app/views/user_mailer/delete_work_notification.html.erb
+++ b/app/views/user_mailer/delete_work_notification.html.erb
@@ -1,5 +1,5 @@
<% content_for :message do %>
- <%= t("mailer.general.greeting.formal", name: style_bold(@user.login)).html_safe %> <%= t("mailer.general.greeting.formal_html", name: style_bold(@user.login)) %> <%= (@work.pseuds.count > 1 && @user != User.current_user) ?
t('.deleted_other.html',
title: style_creation_title(@work.title),
diff --git a/app/views/user_mailer/delete_work_notification.text.erb b/app/views/user_mailer/delete_work_notification.text.erb
index e839db5e822..5fb54567c49 100644
--- a/app/views/user_mailer/delete_work_notification.text.erb
+++ b/app/views/user_mailer/delete_work_notification.text.erb
@@ -1,5 +1,5 @@
<% content_for :message do %>
-<%= t("mailer.general.greeting.formal", name: @user.login) %>
+<%= t("mailer.general.greeting.formal_html", name: @user.login) %>
<%= (@work.pseuds.count > 1 && @user != User.current_user) ?
t('.deleted_other.text',
diff --git a/app/views/user_mailer/feedback.html.erb b/app/views/user_mailer/feedback.html.erb
index ba064d993af..9a8528c2a84 100644
--- a/app/views/user_mailer/feedback.html.erb
+++ b/app/views/user_mailer/feedback.html.erb
@@ -1,8 +1,7 @@
<% content_for :message do %>
<% if @username.present? %>
- <%= t("mailer.general.greeting.informal.addressed",
- name: style_bold(@username)).html_safe %>
+ <%= t("mailer.general.greeting.informal.addressed_html", name: style_bold(@username)) %>
<% else %>
<%= t("mailer.general.greeting.informal.unaddressed") %>
<% end %>
diff --git a/app/views/user_mailer/feedback.text.erb b/app/views/user_mailer/feedback.text.erb
index 3d5b6231786..1c7c67370d1 100644
--- a/app/views/user_mailer/feedback.text.erb
+++ b/app/views/user_mailer/feedback.text.erb
@@ -1,7 +1,7 @@
<% content_for :message do %>
<% if @username.present? %>
-<%= t("mailer.general.greeting.informal.addressed", name: @username) %>
+<%= t("mailer.general.greeting.informal.addressed_html", name: @username) %>
<% else %>
<%= t("mailer.general.greeting.informal.unaddressed") %>
<% end %>
diff --git a/app/views/user_mailer/invite_increase_notification.html.erb b/app/views/user_mailer/invite_increase_notification.html.erb
index f08c0361c75..28f3ec28dfb 100644
--- a/app/views/user_mailer/invite_increase_notification.html.erb
+++ b/app/views/user_mailer/invite_increase_notification.html.erb
@@ -1,5 +1,5 @@
<% content_for :message do %>
- <%= t("mailer.general.greeting.informal.addressed", name: style_bold(@user.login)).html_safe %> <%= t("mailer.general.greeting.informal.addressed_html", name: style_bold(@user.login)) %> <%= t(".html.body", count: @total, invitation_page_link: style_link(t(".invitation_page_link_text"), user_invitations_url(@user))).html_safe %> <%= t("mailer.general.greeting.formal", name: style_bold(@user.login)).html_safe %> <%= t("mailer.general.greeting.formal_html", name: style_bold(@user.login)) %> <%= t(".main", count: @total) %> <%= t(".reason") %> <%= t("mailer.general.greeting.formal", name: style_bold(@user.login)).html_safe %> <%= t("mailer.general.greeting.formal_html", name: style_bold(@user.login)) %> The collection maintainers of <%= style_link(@collection.title, collection_url(@collection)) %> would
like to include your work <%= style_creation_link(@work.title, work_url(@work)) %> in their collection! <%= t("mailer.general.greeting.informal.addressed", name: style_bold(@user.login)).html_safe %> <%= t("mailer.general.greeting.informal.addressed_html", name: style_bold(@user.login)) %>
<% if @collection %>
diff --git a/app/views/user_mailer/recipient_notification.text.erb b/app/views/user_mailer/recipient_notification.text.erb
index 1625aba911c..c1c39a3d9c8 100644
--- a/app/views/user_mailer/recipient_notification.text.erb
+++ b/app/views/user_mailer/recipient_notification.text.erb
@@ -1,5 +1,5 @@
<% content_for :message do %>
-<%= t("mailer.general.greeting.informal.addressed", name: @user.login) %>
+<%= t("mailer.general.greeting.informal.addressed_html", name: @user.login) %>
<% if @collection %>
<%= t(".text.collection", collection_title: @collection.title, collection_url: collection_url(@collection)) %>
diff --git a/app/views/users/mailer/reset_password_instructions.html.erb b/app/views/users/mailer/reset_password_instructions.html.erb
index a627c242f0d..91e2f46d848 100644
--- a/app/views/users/mailer/reset_password_instructions.html.erb
+++ b/app/views/users/mailer/reset_password_instructions.html.erb
@@ -1,5 +1,5 @@
<% content_for :message do %>
- <%= t("mailer.general.greeting.formal", name: style_bold(@resource.login)).html_safe %> <%= t("mailer.general.greeting.formal_html", name: style_bold(@resource.login)) %> <%= t(".intro") %> <%= style_link t(".link_title"), edit_user_password_url(reset_password_token: @token).html_safe %> <%= t(".expiration") %> <%= t(".no_creations") %> Neener <%= t("mailer.general.greeting.formal_html", name: style_bold(@resource.login)) %> <%= t(".intro") %> <%= style_link t(".link_title"), edit_user_password_url(reset_password_token: @token).html_safe %> <%= style_link t(".link_title"), edit_user_password_url(reset_password_token: @token) %> <%= t(".expiration") %> <%= t(".unrequested") %>
diff --git a/app/views/user_mailer/feedback.text.erb b/app/views/user_mailer/feedback.text.erb
index cfa8ba0c942..3d5b6231786 100644
--- a/app/views/user_mailer/feedback.text.erb
+++ b/app/views/user_mailer/feedback.text.erb
@@ -6,10 +6,7 @@
<%= t("mailer.general.greeting.informal.unaddressed") %>
<% end %>
-We're working hard to reply to everyone, and we'll respond to you as soon as we can.
-Your communication is greatly valued, and it will be reviewed and answered
-by our volunteer Support team. In the meantime, here is a copy of the
-information you submitted through the Technical Support and Feedback form:
+<%= t(".introduction") %>
<%= text_divider %>
@@ -18,8 +15,7 @@ information you submitted through the Technical Support and Feedback form:
<%= text_divider %>
-If you have additional questions or information, do not hesitate to send in
-another ticket.
+<%= t(".additional_ticket") %>
<%= t("mailer.general.closing.formal") %>
<%= t("mailer.general.signature.support") %>
diff --git a/config/locales/mailers/en.yml b/config/locales/mailers/en.yml
index b612c6b6c4b..3ca6f63d45f 100644
--- a/config/locales/mailers/en.yml
+++ b/config/locales/mailers/en.yml
@@ -313,6 +313,9 @@ en:
text: If you have questions, please %{support} (%{url}).
subject: "[%{app_name}] Your work has been deleted"
support: contact Support
+ feedback:
+ additional_ticket: If you have additional questions or information, do not hesitate to send in another ticket.
+ introduction: 'We''re working hard to reply to everyone, and we''ll respond to you as soon as we can. Your communication is greatly valued, and it will be reviewed and answered by our volunteer Support team. In the meantime, here is a copy of the information you submitted through the Technical Support and Feedback form:'
invitation:
been_invited: You've been invited to join the Archive of Our Own!
features: With an account, you can post fanworks, use bookmarks to keep track of works you enjoyed, receive subscription emails when your favorite creators or works update, customize the way the site looks for you, and more!
diff --git a/features/other_b/support.feature b/features/other_b/support.feature
index 3da8e410210..060c38db00e 100644
--- a/features/other_b/support.feature
+++ b/features/other_b/support.feature
@@ -16,7 +16,8 @@ Feature: Filing a support request
And I press "Send"
Then I should see "Your message was sent to the Archive team - thank you!"
And 1 email should be delivered
- And the email should contain "We're working hard to reply to everyone, and we'll respond to you as soon as we can."
+ And the email should contain "working hard to reply to everyone"
+ And the email should contain "respond to you as soon as we can."
And the email should contain "If you have additional questions or information"
And the email should contain "Sent at Mon, 14 Mar 2022 12:00:00 \+0000"
When I follow "Support & Feedback"
diff --git a/spec/mailers/user_mailer_spec.rb b/spec/mailers/user_mailer_spec.rb
index 8989d34f966..13324a80cd2 100644
--- a/spec/mailers/user_mailer_spec.rb
+++ b/spec/mailers/user_mailer_spec.rb
@@ -703,6 +703,7 @@
# Test both body contents
it_behaves_like "a multipart email"
+ it_behaves_like "a translated email"
describe "HTML version" do
it "has the correct content" do
@@ -734,6 +735,7 @@
# Test both body contents
it_behaves_like "a multipart email"
+ it_behaves_like "a translated email"
describe "HTML version" do
it "has the correct content" do
diff --git a/test/mailers/previews/user_mailer_preview.rb b/test/mailers/previews/user_mailer_preview.rb
index 006547dea1e..ebf7fd87531 100644
--- a/test/mailers/previews/user_mailer_preview.rb
+++ b/test/mailers/previews/user_mailer_preview.rb
@@ -24,7 +24,7 @@ def creatorship_request
end
# Sent to a user when the submit a support request (AKA feedback)
- def feedback_response
+ def feedback
feedback = create(:feedback)
UserMailer.feedback(feedback.id)
end
From 47cc03880769f4256456598e94eed99a8d6e0faf Mon Sep 17 00:00:00 2001
From: sarken <%= link_to ts("AO3 News"), admin_posts_path %>
+ <%= link_to t(".page_heading"), admin_posts_path %>
- <%= ts("Admin Actions") %>
-
-
<%= t(".navigation.admin.landmark") %>
+
+
<% end %>
- <%= ts("News Post Navigation") %>
-
+
<% end %>
@@ -50,9 +40,6 @@
<%= render "bookmarks/bookmark_user_module", bookmark: bookmark %>
- <% # recent bookmarks will be loaded up here if requested %>
- <%= t(".navigation.landmark") %>
+
<% if @previous_admin_post %>
-
<% end %>
@@ -40,6 +50,9 @@
<%= render "bookmarks/bookmark_user_module", bookmark: bookmark %>
+ <% # recent bookmarks will be loaded up here if requested %>
+ <%= ts("Unreviewed Comments on") %> <%= link_to(@commentable.commentable_name, @commentable) %>
+<%= t(".page_heading_html", commentable_link: link_to(@commentable.commentable_name, @commentable)) %>
-
-
diff --git a/app/views/user_mailer/feedback.text.erb b/app/views/user_mailer/feedback.text.erb
index 3d5b6231786..cfa8ba0c942 100644
--- a/app/views/user_mailer/feedback.text.erb
+++ b/app/views/user_mailer/feedback.text.erb
@@ -6,7 +6,10 @@
<%= t("mailer.general.greeting.informal.unaddressed") %>
<% end %>
-<%= t(".introduction") %>
+We're working hard to reply to everyone, and we'll respond to you as soon as we can.
+Your communication is greatly valued, and it will be reviewed and answered
+by our volunteer Support team. In the meantime, here is a copy of the
+information you submitted through the Technical Support and Feedback form:
<%= text_divider %>
@@ -15,7 +18,8 @@
<%= text_divider %>
-<%= t(".additional_ticket") %>
+If you have additional questions or information, do not hesitate to send in
+another ticket.
<%= t("mailer.general.closing.formal") %>
<%= t("mailer.general.signature.support") %>
diff --git a/config/locales/mailers/en.yml b/config/locales/mailers/en.yml
index 3ca6f63d45f..b612c6b6c4b 100644
--- a/config/locales/mailers/en.yml
+++ b/config/locales/mailers/en.yml
@@ -313,9 +313,6 @@ en:
text: If you have questions, please %{support} (%{url}).
subject: "[%{app_name}] Your work has been deleted"
support: contact Support
- feedback:
- additional_ticket: If you have additional questions or information, do not hesitate to send in another ticket.
- introduction: 'We''re working hard to reply to everyone, and we''ll respond to you as soon as we can. Your communication is greatly valued, and it will be reviewed and answered by our volunteer Support team. In the meantime, here is a copy of the information you submitted through the Technical Support and Feedback form:'
invitation:
been_invited: You've been invited to join the Archive of Our Own!
features: With an account, you can post fanworks, use bookmarks to keep track of works you enjoyed, receive subscription emails when your favorite creators or works update, customize the way the site looks for you, and more!
diff --git a/features/other_b/support.feature b/features/other_b/support.feature
index 060c38db00e..3da8e410210 100644
--- a/features/other_b/support.feature
+++ b/features/other_b/support.feature
@@ -16,8 +16,7 @@ Feature: Filing a support request
And I press "Send"
Then I should see "Your message was sent to the Archive team - thank you!"
And 1 email should be delivered
- And the email should contain "working hard to reply to everyone"
- And the email should contain "respond to you as soon as we can."
+ And the email should contain "We're working hard to reply to everyone, and we'll respond to you as soon as we can."
And the email should contain "If you have additional questions or information"
And the email should contain "Sent at Mon, 14 Mar 2022 12:00:00 \+0000"
When I follow "Support & Feedback"
diff --git a/spec/mailers/user_mailer_spec.rb b/spec/mailers/user_mailer_spec.rb
index 13324a80cd2..8989d34f966 100644
--- a/spec/mailers/user_mailer_spec.rb
+++ b/spec/mailers/user_mailer_spec.rb
@@ -703,7 +703,6 @@
# Test both body contents
it_behaves_like "a multipart email"
- it_behaves_like "a translated email"
describe "HTML version" do
it "has the correct content" do
@@ -735,7 +734,6 @@
# Test both body contents
it_behaves_like "a multipart email"
- it_behaves_like "a translated email"
describe "HTML version" do
it "has the correct content" do
diff --git a/test/mailers/previews/user_mailer_preview.rb b/test/mailers/previews/user_mailer_preview.rb
index ebf7fd87531..006547dea1e 100644
--- a/test/mailers/previews/user_mailer_preview.rb
+++ b/test/mailers/previews/user_mailer_preview.rb
@@ -24,7 +24,7 @@ def creatorship_request
end
# Sent to a user when the submit a support request (AKA feedback)
- def feedback
+ def feedback_response
feedback = create(:feedback)
UserMailer.feedback(feedback.id)
end
From 091620da6b6dbbdacec05e925276bd5f78e3a7bb Mon Sep 17 00:00:00 2001
From: sarken
+ <%= render partial: 'bookmarks/bookmark_blurb_short', collection: @bookmarks, as: :bookmark %>
+
+
+<% elsif @bookmarkable %>
<% # show only partial view for each bookmark since the bookmarked object is already shown above %>
<%= render partial: 'bookmarks/bookmark_blurb_short', collection: @bookmarks, as: :bookmark %>
diff --git a/app/views/bookmarks/fetch_recent.js.erb b/app/views/bookmarks/fetch_recent.js.erb
new file mode 100644
index 00000000000..11b38a5a70b
--- /dev/null
+++ b/app/views/bookmarks/fetch_recent.js.erb
@@ -0,0 +1,8 @@
+$j('#recent_<%= "#{@bookmark.bookmarkable_type.underscore}_#{@bookmark.id}"%>').html('<%= escape_javascript(render "bookmarks", :params => {:show_recent => true}) %>').slideDown();
+<% if @bookmark.bookmarkable.bookmarks.size > 5 %>
+ $j('#recent_<%= "#{@bookmark.bookmarkable_type.underscore}_#{@bookmark.id}"%>').append('<%= escape_javascript(link_to(ts("All Bookmarks"), eval(@bookmark.bookmarkable.class.to_s.underscore + "_bookmarks_path(@bookmark.bookmarkable)"), :class => "action")) %>');
+ $j('#recent_<%= "#{@bookmark.bookmarkable_type.underscore}_#{@bookmark.id}"%>').append(" ");
+<% end %>
+$j('#recent_<%= "#{@bookmark.bookmarkable_type.underscore}_#{@bookmark.id}"%>').append('<%= escape_javascript(link_to(ts("Hide Most Recent Bookmarks"), hide_recent_bookmarks_path(@bookmark), :method => :get, :remote => true, :class => "action")) %>');
+$j('#recent_link_<%= "#{@bookmark.bookmarkable_type.underscore}_#{@bookmark.id}"%>').html('<%= escape_javascript(link_to(ts("Hide Most Recent Bookmarks"), hide_recent_bookmarks_path(@bookmark), :method => :get, :remote => true, :class => "action")) %>');
+$j('#recent_<%= "#{@bookmark.bookmarkable_type.underscore}_#{@bookmark.id}"%>').slideDown();
diff --git a/app/views/bookmarks/hide_recent.js.erb b/app/views/bookmarks/hide_recent.js.erb
new file mode 100644
index 00000000000..4eaf03574b1
--- /dev/null
+++ b/app/views/bookmarks/hide_recent.js.erb
@@ -0,0 +1,3 @@
+$j('#recent_<%= "#{@bookmark.bookmarkable_type.underscore}_#{@bookmark.id}"%>').slideUp();
+$j('#recent_<%= "#{@bookmark.bookmarkable_type.underscore}_#{@bookmark.id}"%>').html("");
+$j('#recent_link_<%= "#{@bookmark.bookmarkable_type.underscore}_#{@bookmark.id}"%>').html('<%= escape_javascript(link_to(ts("Show Most Recent Bookmarks"), fetch_recent_bookmarks_path(@bookmark, fetch: true), :method => :get, :remote => true)) %>');
diff --git a/config/routes.rb b/config/routes.rb
index d67b8dab288..5ea912a4cf3 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -654,6 +654,9 @@
# can be refactored to not rely on their existence.
#
# Note written on August 1, 2017 during upgrade to Rails 5.1.
+ get '/bookmarks/fetch_recent/:id' => 'bookmarks#fetch_recent', as: :fetch_recent_bookmarks
+ get '/bookmarks/hide_recent/:id' => 'bookmarks#hide_recent', as: :hide_recent_bookmarks
+
get '/invite_requests/show' => 'invite_requests#show', as: :show_invite_request
get '/user_invite_requests/update' => 'user_invite_requests#update'
diff --git a/features/bookmarks/bookmark_create.feature b/features/bookmarks/bookmark_create.feature
index 56872fb0d48..e56da0f057c 100644
--- a/features/bookmarks/bookmark_create.feature
+++ b/features/bookmarks/bookmark_create.feature
@@ -410,6 +410,27 @@ Scenario: I cannot edit an existing bookmark to transfer it to a pseud I don't o
Then I should not see "Bookmark was successfully updated"
And I should see "You can't bookmark with that pseud."
+@javascript
+Scenario: Can use "Show Most Recent Bookmarks" from the bookmarks page
+ Given the work "Popular Work"
+ And I am logged in as "bookmarker1"
+ And I bookmark the work "Popular Work" with the note "Love it"
+ And I log out
+ And I am logged in as "bookmarker2"
+ And I bookmark the work "Popular Work"
+ And the statistics for the work "Popular Work" are updated
+ When I am on the bookmarks page
+ # Follow the link for bookmarker2's bookmark, which is more recent.
+ And I follow "Show Most Recent Bookmarks" within ".bookmark.blurb:first-child"
+ Then I should see "bookmarker1" within ".bookmark.blurb:first-child .recent"
+ And I should see "Love it" within ".bookmark.blurb:first-child .recent"
+ And I should see "Hide Most Recent Bookmarks" within ".bookmark.blurb:first-child .recent"
+ When I follow "Hide Most Recent Bookmarks" within ".bookmark.blurb:first-child .recent"
+ # .recent has been hidden, we should not see its contents anymore.
+ Then I should not see "bookmarker1" within ".bookmark.blurb:first-child"
+ And I should not see "Love it" within ".bookmark.blurb:first-child"
+ And I should see "Show Most Recent Bookmarks" within ".bookmark.blurb:first-child"
+
Scenario: A bookmark with duplicate tags other than capitalization has only first version of tag saved
Given I am logged in as "bookmark_user"
When I post the work "Revenge of the Sith"
diff --git a/public/stylesheets/masters/low_vision_default/low_vision_default_site_screen_.css b/public/stylesheets/masters/low_vision_default/low_vision_default_site_screen_.css
index 17bfbf566a3..91877eb07fd 100644
--- a/public/stylesheets/masters/low_vision_default/low_vision_default_site_screen_.css
+++ b/public/stylesheets/masters/low_vision_default/low_vision_default_site_screen_.css
@@ -37,7 +37,8 @@ form blockquote.userstuff {
#inner .filters,
#footer,
.filters dt,
-media .listbox {
+media .listbox,
+.bookmark .recent .index {
width: 100%;
}
@@ -158,3 +159,8 @@ pre {
background: #ccc;
color: #111;
}
+
+.bookmark .recent,
+.bookmark .recent .index {
+ border: none;
+}
diff --git a/public/stylesheets/site/2.0/13-group-blurb.css b/public/stylesheets/site/2.0/13-group-blurb.css
index 63d317989d6..e1b43eda370 100644
--- a/public/stylesheets/site/2.0/13-group-blurb.css
+++ b/public/stylesheets/site/2.0/13-group-blurb.css
@@ -332,7 +332,7 @@ blurbs on the manage collection items pages, mostly reseting styles inherited fr
top: 28px;
}
-.bookmark div.user {
+.bookmark div.user, .bookmark div.recent {
clear: right;
box-sizing: border-box;
}
@@ -398,6 +398,11 @@ blurbs on the manage collection items pages, mostly reseting styles inherited fr
position: static;
}
+.bookmark .recent .index {
+ float: none;
+ width: 100%;
+}
+
/* mod: READING */
.reading .user {
From 2d2a31b45b94984e2716e2983c0c4fbc14805cf2 Mon Sep 17 00:00:00 2001
From: sarken
-
diff --git a/app/views/series/show.html.erb b/app/views/series/show.html.erb
index 029c3731d80..4d87bbf92ff 100644
--- a/app/views/series/show.html.erb
+++ b/app/views/series/show.html.erb
@@ -58,15 +58,15 @@
-
-
diff --git a/app/views/series/show.html.erb b/app/views/series/show.html.erb
index 4d87bbf92ff..029c3731d80 100644
--- a/app/views/series/show.html.erb
+++ b/app/views/series/show.html.erb
@@ -58,15 +58,15 @@
-
- <%= render partial: 'bookmarks/bookmark_blurb_short', collection: @bookmarks, as: :bookmark %>
-
-
-<% elsif @bookmarkable %>
+<% if @bookmarkable %>
<% # show only partial view for each bookmark since the bookmarked object is already shown above %>
<%= render partial: 'bookmarks/bookmark_blurb_short', collection: @bookmarks, as: :bookmark %>
diff --git a/app/views/bookmarks/fetch_recent.js.erb b/app/views/bookmarks/fetch_recent.js.erb
deleted file mode 100644
index 11b38a5a70b..00000000000
--- a/app/views/bookmarks/fetch_recent.js.erb
+++ /dev/null
@@ -1,8 +0,0 @@
-$j('#recent_<%= "#{@bookmark.bookmarkable_type.underscore}_#{@bookmark.id}"%>').html('<%= escape_javascript(render "bookmarks", :params => {:show_recent => true}) %>').slideDown();
-<% if @bookmark.bookmarkable.bookmarks.size > 5 %>
- $j('#recent_<%= "#{@bookmark.bookmarkable_type.underscore}_#{@bookmark.id}"%>').append('<%= escape_javascript(link_to(ts("All Bookmarks"), eval(@bookmark.bookmarkable.class.to_s.underscore + "_bookmarks_path(@bookmark.bookmarkable)"), :class => "action")) %>');
- $j('#recent_<%= "#{@bookmark.bookmarkable_type.underscore}_#{@bookmark.id}"%>').append(" ");
-<% end %>
-$j('#recent_<%= "#{@bookmark.bookmarkable_type.underscore}_#{@bookmark.id}"%>').append('<%= escape_javascript(link_to(ts("Hide Most Recent Bookmarks"), hide_recent_bookmarks_path(@bookmark), :method => :get, :remote => true, :class => "action")) %>');
-$j('#recent_link_<%= "#{@bookmark.bookmarkable_type.underscore}_#{@bookmark.id}"%>').html('<%= escape_javascript(link_to(ts("Hide Most Recent Bookmarks"), hide_recent_bookmarks_path(@bookmark), :method => :get, :remote => true, :class => "action")) %>');
-$j('#recent_<%= "#{@bookmark.bookmarkable_type.underscore}_#{@bookmark.id}"%>').slideDown();
diff --git a/app/views/bookmarks/hide_recent.js.erb b/app/views/bookmarks/hide_recent.js.erb
deleted file mode 100644
index 4eaf03574b1..00000000000
--- a/app/views/bookmarks/hide_recent.js.erb
+++ /dev/null
@@ -1,3 +0,0 @@
-$j('#recent_<%= "#{@bookmark.bookmarkable_type.underscore}_#{@bookmark.id}"%>').slideUp();
-$j('#recent_<%= "#{@bookmark.bookmarkable_type.underscore}_#{@bookmark.id}"%>').html("");
-$j('#recent_link_<%= "#{@bookmark.bookmarkable_type.underscore}_#{@bookmark.id}"%>').html('<%= escape_javascript(link_to(ts("Show Most Recent Bookmarks"), fetch_recent_bookmarks_path(@bookmark, fetch: true), :method => :get, :remote => true)) %>');
diff --git a/config/routes.rb b/config/routes.rb
index 5ea912a4cf3..d67b8dab288 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -654,9 +654,6 @@
# can be refactored to not rely on their existence.
#
# Note written on August 1, 2017 during upgrade to Rails 5.1.
- get '/bookmarks/fetch_recent/:id' => 'bookmarks#fetch_recent', as: :fetch_recent_bookmarks
- get '/bookmarks/hide_recent/:id' => 'bookmarks#hide_recent', as: :hide_recent_bookmarks
-
get '/invite_requests/show' => 'invite_requests#show', as: :show_invite_request
get '/user_invite_requests/update' => 'user_invite_requests#update'
diff --git a/features/bookmarks/bookmark_create.feature b/features/bookmarks/bookmark_create.feature
index e56da0f057c..56872fb0d48 100644
--- a/features/bookmarks/bookmark_create.feature
+++ b/features/bookmarks/bookmark_create.feature
@@ -410,27 +410,6 @@ Scenario: I cannot edit an existing bookmark to transfer it to a pseud I don't o
Then I should not see "Bookmark was successfully updated"
And I should see "You can't bookmark with that pseud."
-@javascript
-Scenario: Can use "Show Most Recent Bookmarks" from the bookmarks page
- Given the work "Popular Work"
- And I am logged in as "bookmarker1"
- And I bookmark the work "Popular Work" with the note "Love it"
- And I log out
- And I am logged in as "bookmarker2"
- And I bookmark the work "Popular Work"
- And the statistics for the work "Popular Work" are updated
- When I am on the bookmarks page
- # Follow the link for bookmarker2's bookmark, which is more recent.
- And I follow "Show Most Recent Bookmarks" within ".bookmark.blurb:first-child"
- Then I should see "bookmarker1" within ".bookmark.blurb:first-child .recent"
- And I should see "Love it" within ".bookmark.blurb:first-child .recent"
- And I should see "Hide Most Recent Bookmarks" within ".bookmark.blurb:first-child .recent"
- When I follow "Hide Most Recent Bookmarks" within ".bookmark.blurb:first-child .recent"
- # .recent has been hidden, we should not see its contents anymore.
- Then I should not see "bookmarker1" within ".bookmark.blurb:first-child"
- And I should not see "Love it" within ".bookmark.blurb:first-child"
- And I should see "Show Most Recent Bookmarks" within ".bookmark.blurb:first-child"
-
Scenario: A bookmark with duplicate tags other than capitalization has only first version of tag saved
Given I am logged in as "bookmark_user"
When I post the work "Revenge of the Sith"
diff --git a/public/stylesheets/masters/low_vision_default/low_vision_default_site_screen_.css b/public/stylesheets/masters/low_vision_default/low_vision_default_site_screen_.css
index 91877eb07fd..17bfbf566a3 100644
--- a/public/stylesheets/masters/low_vision_default/low_vision_default_site_screen_.css
+++ b/public/stylesheets/masters/low_vision_default/low_vision_default_site_screen_.css
@@ -37,8 +37,7 @@ form blockquote.userstuff {
#inner .filters,
#footer,
.filters dt,
-media .listbox,
-.bookmark .recent .index {
+media .listbox {
width: 100%;
}
@@ -159,8 +158,3 @@ pre {
background: #ccc;
color: #111;
}
-
-.bookmark .recent,
-.bookmark .recent .index {
- border: none;
-}
diff --git a/public/stylesheets/site/2.0/13-group-blurb.css b/public/stylesheets/site/2.0/13-group-blurb.css
index e1b43eda370..63d317989d6 100644
--- a/public/stylesheets/site/2.0/13-group-blurb.css
+++ b/public/stylesheets/site/2.0/13-group-blurb.css
@@ -332,7 +332,7 @@ blurbs on the manage collection items pages, mostly reseting styles inherited fr
top: 28px;
}
-.bookmark div.user, .bookmark div.recent {
+.bookmark div.user {
clear: right;
box-sizing: border-box;
}
@@ -398,11 +398,6 @@ blurbs on the manage collection items pages, mostly reseting styles inherited fr
position: static;
}
-.bookmark .recent .index {
- float: none;
- width: 100%;
-}
-
/* mod: READING */
.reading .user {
From a013e766aece66e4ad0798a419770d3757674983 Mon Sep 17 00:00:00 2001
From: sarken
diff --git a/app/views/user_mailer/feedback.text.erb b/app/views/user_mailer/feedback.text.erb
index cfa8ba0c942..3d5b6231786 100644
--- a/app/views/user_mailer/feedback.text.erb
+++ b/app/views/user_mailer/feedback.text.erb
@@ -6,10 +6,7 @@
<%= t("mailer.general.greeting.informal.unaddressed") %>
<% end %>
-We're working hard to reply to everyone, and we'll respond to you as soon as we can.
-Your communication is greatly valued, and it will be reviewed and answered
-by our volunteer Support team. In the meantime, here is a copy of the
-information you submitted through the Technical Support and Feedback form:
+<%= t(".introduction") %>
<%= text_divider %>
@@ -18,8 +15,7 @@ information you submitted through the Technical Support and Feedback form:
<%= text_divider %>
-If you have additional questions or information, do not hesitate to send in
-another ticket.
+<%= t(".additional_ticket") %>
<%= t("mailer.general.closing.formal") %>
<%= t("mailer.general.signature.support") %>
diff --git a/config/locales/mailers/en.yml b/config/locales/mailers/en.yml
index b612c6b6c4b..3ca6f63d45f 100644
--- a/config/locales/mailers/en.yml
+++ b/config/locales/mailers/en.yml
@@ -313,6 +313,9 @@ en:
text: If you have questions, please %{support} (%{url}).
subject: "[%{app_name}] Your work has been deleted"
support: contact Support
+ feedback:
+ additional_ticket: If you have additional questions or information, do not hesitate to send in another ticket.
+ introduction: 'We''re working hard to reply to everyone, and we''ll respond to you as soon as we can. Your communication is greatly valued, and it will be reviewed and answered by our volunteer Support team. In the meantime, here is a copy of the information you submitted through the Technical Support and Feedback form:'
invitation:
been_invited: You've been invited to join the Archive of Our Own!
features: With an account, you can post fanworks, use bookmarks to keep track of works you enjoyed, receive subscription emails when your favorite creators or works update, customize the way the site looks for you, and more!
diff --git a/features/other_b/support.feature b/features/other_b/support.feature
index 3da8e410210..060c38db00e 100644
--- a/features/other_b/support.feature
+++ b/features/other_b/support.feature
@@ -16,7 +16,8 @@ Feature: Filing a support request
And I press "Send"
Then I should see "Your message was sent to the Archive team - thank you!"
And 1 email should be delivered
- And the email should contain "We're working hard to reply to everyone, and we'll respond to you as soon as we can."
+ And the email should contain "working hard to reply to everyone"
+ And the email should contain "respond to you as soon as we can."
And the email should contain "If you have additional questions or information"
And the email should contain "Sent at Mon, 14 Mar 2022 12:00:00 \+0000"
When I follow "Support & Feedback"
diff --git a/spec/mailers/user_mailer_spec.rb b/spec/mailers/user_mailer_spec.rb
index 8989d34f966..13324a80cd2 100644
--- a/spec/mailers/user_mailer_spec.rb
+++ b/spec/mailers/user_mailer_spec.rb
@@ -703,6 +703,7 @@
# Test both body contents
it_behaves_like "a multipart email"
+ it_behaves_like "a translated email"
describe "HTML version" do
it "has the correct content" do
@@ -734,6 +735,7 @@
# Test both body contents
it_behaves_like "a multipart email"
+ it_behaves_like "a translated email"
describe "HTML version" do
it "has the correct content" do
diff --git a/test/mailers/previews/user_mailer_preview.rb b/test/mailers/previews/user_mailer_preview.rb
index 006547dea1e..ebf7fd87531 100644
--- a/test/mailers/previews/user_mailer_preview.rb
+++ b/test/mailers/previews/user_mailer_preview.rb
@@ -24,7 +24,7 @@ def creatorship_request
end
# Sent to a user when the submit a support request (AKA feedback)
- def feedback_response
+ def feedback
feedback = create(:feedback)
UserMailer.feedback(feedback.id)
end
From 5d710e6883c26d7782d14680d73e5307421a28e5 Mon Sep 17 00:00:00 2001
From: sarken <%= ts("Orphan All Works") %>
-<%= ts('About the') %> "><%= ts("OTW") %>
+<%= t(".heading.html", otw: tag.abbr(t(".heading.otw"), title: t(".heading.otw_long"))) %>
-
- <%= t(".time.title") %>
- <%= t(".money.title") %>
diff --git a/factories/wrangling_assignments.rb b/factories/wrangling_assignments.rb
new file mode 100644
index 00000000000..1373dc4271f
--- /dev/null
+++ b/factories/wrangling_assignments.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :wrangling_assignment do
+ user
+ fandom
+ end
+end
diff --git a/features/tags_and_wrangling/tag_wrangling_admin.feature b/features/tags_and_wrangling/tag_wrangling_admin.feature
index d412cbff6f0..5d70da67b07 100644
--- a/features/tags_and_wrangling/tag_wrangling_admin.feature
+++ b/features/tags_and_wrangling/tag_wrangling_admin.feature
@@ -54,7 +54,7 @@ Feature: Tag wrangling
Scenario: Admin can remove a user's wrangling assignments
Given the tag wrangler "tangler" with password "wr@ngl3r" is wrangler of "Testing"
- When I am logged in as an admin
+ When I am logged in as a "tag_wrangling" admin
And I am on the wranglers page
And I follow "x"
Then I should see "Wranglers were successfully unassigned!"
diff --git a/spec/controllers/tag_wranglers_controller_spec.rb b/spec/controllers/tag_wranglers_controller_spec.rb
index 60a9f3a129a..4b4a58594ef 100644
--- a/spec/controllers/tag_wranglers_controller_spec.rb
+++ b/spec/controllers/tag_wranglers_controller_spec.rb
@@ -4,8 +4,69 @@
include LoginMacros
include RedirectExpectationHelper
+ wrangling_roles = %w[superadmin tag_wrangling]
+
let(:user) { create(:tag_wrangler) }
+ shared_examples "denies access to unauthorized admins" do
+ context "when logged in as an admin with no role" do
+ let(:admin) { create(:admin) }
+
+ it "redirects with an error" do
+ it_redirects_to_with_error(root_url, "Sorry, only an authorized admin can access the page you were trying to reach.")
+ end
+ end
+
+ (Admin::VALID_ROLES - wrangling_roles).each do |admin_role|
+ context "when logged in as an admin with role #{admin_role}" do
+ let(:admin) { create(:admin, roles: [admin_role]) }
+
+ it "redirects with an error" do
+ it_redirects_to_with_error(root_url, "Sorry, only an authorized admin can access the page you were trying to reach.")
+ end
+ end
+ end
+ end
+
+ describe "#index" do
+ before do
+ Role.create!(name: "tag_wrangler")
+ end
+
+ it_behaves_like "denies access to unauthorized admins" do
+ before do
+ fake_login_admin(admin)
+ get :index
+ end
+ end
+
+ wrangling_roles.each do |admin_role|
+ context "when logged in as an admin with role #{admin_role}" do
+ let(:admin) { create(:admin, roles: [admin_role]) }
+
+ before do
+ fake_login_admin(admin)
+ end
+
+ it "allows access" do
+ get :index
+ expect(response).to have_http_status(:success)
+ end
+ end
+ end
+
+ context "when logged in as a tag wrangler" do
+ before do
+ fake_login_known_user(user)
+ end
+
+ it "allows access" do
+ get :index
+ expect(response).to have_http_status(:success)
+ end
+ end
+ end
+
describe "#show" do
before { fake_login_known_user(user) }
@@ -16,6 +77,28 @@
end.to raise_exception(ActiveRecord::RecordNotFound)
end
end
+
+ it_behaves_like "denies access to unauthorized admins" do
+ before do
+ fake_login_admin(admin)
+ get :show, params: { id: user.login }
+ end
+ end
+
+ wrangling_roles.each do |admin_role|
+ context "when logged in as an admin with role #{admin_role}" do
+ let(:admin) { create(:admin, roles: [admin_role]) }
+
+ before do
+ fake_login_admin(admin)
+ end
+
+ it "allows access" do
+ get :show, params: { id: user.login }
+ expect(response).to have_http_status(:success)
+ end
+ end
+ end
end
describe "#report_csv" do
@@ -36,28 +119,17 @@
it_behaves_like "prevents access to the report"
end
- context "when logged in as an admin without proper authorization" do
- before { fake_login_admin(admin) }
-
- context "with no role" do
- let(:admin) { create(:admin) }
-
- it_behaves_like "prevents access to the report"
- end
-
- (Admin::VALID_ROLES - %w[superadmin tag_wrangling]).each do |admin_role|
- context "with role #{admin_role}" do
- let(:admin) { create(:admin, roles: [admin_role]) }
-
- it_behaves_like "prevents access to the report"
- end
+ it_behaves_like "denies access to unauthorized admins" do
+ before do
+ fake_login_admin(admin)
+ get :report_csv, params: { id: user.login }
end
end
context "when logged in as an admin with proper authorization" do
before { fake_login_admin(admin) }
- %w[superadmin tag_wrangling].each do |admin_role|
+ wrangling_roles.each do |admin_role|
context "with role #{admin_role}" do
let(:admin) { create(:admin, roles: [admin_role]) }
@@ -75,7 +147,7 @@
result = CSV.parse(response.body.encode("utf-8")[1..], col_sep: "\t")
expect(result)
- .to eq([%w[Name Last\ Updated Type Merger Fandoms Unwrangleable],
+ .to eq([["Name", "Last Updated", "Type", "Merger", "Fandoms", "Unwrangleable"],
[tag1.name, tag1.updated_at.to_s, tag1.type, "", "", "false"]])
end
@@ -100,7 +172,7 @@
result = CSV.parse(response.body.encode("utf-8")[1..], col_sep: "\t")
expect(result)
- .to eq([%w[Name Last\ Updated Type Merger Fandoms Unwrangleable],
+ .to eq([["Name", "Last Updated", "Type", "Merger", "Fandoms", "Unwrangleable"],
[tag2.name, tag2.updated_at.to_s, tag2.type, tag1.name, "", "false"],
[tag1.name, tag1.updated_at.to_s, tag1.type, "", "", "false"]])
end
@@ -114,7 +186,7 @@
result = CSV.parse(response.body.encode("utf-8")[1..], col_sep: "\t")
expect(result)
- .to eq([%w[Name Last\ Updated Type Merger Fandoms Unwrangleable],
+ .to eq([["Name", "Last Updated", "Type", "Merger", "Fandoms", "Unwrangleable"],
[tag.name, tag.updated_at.to_s, tag.type, "", fandom.name, "false"]])
end
@@ -129,7 +201,7 @@
result = CSV.parse(response.body.encode("utf-8")[1..], col_sep: "\t")
expect(result)
- .to eq([%w[Name Last\ Updated Type Merger Fandoms Unwrangleable],
+ .to eq([["Name", "Last Updated", "Type", "Merger", "Fandoms", "Unwrangleable"],
[tag.name, tag.updated_at.to_s, tag.type, "", "#{fandom1.name}, #{fandom2.name}", "false"]])
end
@@ -151,11 +223,85 @@
result = CSV.parse(response.body.encode("utf-8")[1..], col_sep: "\t")
expect(result)
- .to eq([%w[Name Last\ Updated Type Merger Fandoms Unwrangleable],
+ .to eq([["Name", "Last Updated", "Type", "Merger", "Fandoms", "Unwrangleable"],
[tag.name, tag.updated_at.to_s, tag.type, "", "", "true"]])
end
end
end
end
end
+
+ describe "#create" do
+ let(:fandom) { create(:fandom) }
+
+ it_behaves_like "denies access to unauthorized admins" do
+ before do
+ fake_login_admin(admin)
+ post :create, params: { assignments: { fandom.id.to_s => [user.login] } }
+ end
+ end
+
+ wrangling_roles.each do |admin_role|
+ context "when logged in as an admin with role #{admin_role}" do
+ let(:admin) { create(:admin, roles: [admin_role]) }
+
+ before do
+ fake_login_admin(admin)
+ end
+
+ it "creates wrangling assignments" do
+ post :create, params: { assignments: { fandom.id.to_s => [user.login] } }
+ it_redirects_to_with_notice(tag_wranglers_path, "Wranglers were successfully assigned!")
+ end
+ end
+ end
+
+ context "when logged in as another tag wrangler" do
+ before do
+ fake_login_known_user(create(:tag_wrangler))
+ end
+
+ it "allows access" do
+ post :create, params: { assignments: { fandom.id.to_s => [user.login] } }
+ it_redirects_to_with_notice(tag_wranglers_path, "Wranglers were successfully assigned!")
+ end
+ end
+ end
+
+ describe "#destroy" do
+ let(:wrangling_assignment) { create(:wrangling_assignment) }
+
+ it_behaves_like "denies access to unauthorized admins" do
+ before do
+ fake_login_admin(admin)
+ delete :destroy, params: { id: wrangling_assignment.user.login, fandom_id: wrangling_assignment.fandom.id }
+ end
+ end
+
+ wrangling_roles.each do |admin_role|
+ context "when logged in as an admin with role #{admin_role}" do
+ let(:admin) { create(:admin, roles: [admin_role]) }
+
+ before do
+ fake_login_admin(admin)
+ end
+
+ it "removes the wrangling assignment" do
+ delete :destroy, params: { id: wrangling_assignment.user.login, fandom_id: wrangling_assignment.fandom.id }
+ it_redirects_to_with_notice(tag_wranglers_path, "Wranglers were successfully unassigned!")
+ end
+ end
+ end
+
+ context "when logged in as another tag wrangler" do
+ before do
+ fake_login_known_user(create(:tag_wrangler))
+ end
+
+ it "allows access" do
+ delete :destroy, params: { id: wrangling_assignment.user.login, fandom_id: wrangling_assignment.fandom.id }
+ it_redirects_to_with_notice(tag_wranglers_path, "Wranglers were successfully unassigned!")
+ end
+ end
+ end
end
From fff3a6d9a34b91d22a8994fff3ab9231e6811627 Mon Sep 17 00:00:00 2001
From: nisha-shaikh <%= ts("API Tokens") %>
+ <%= t(".page_heading") %>
<%= render "navigation" %>
@@ -9,25 +9,25 @@
<%= form_tag url_for(controller: "admin/api", action: "index"), method: :get, class: "search", role: "search" do %>
-
-
- ">
-
">
+
-
@@ -40,7 +40,7 @@
<%= ts("Name") %>
- <%= ts("Token") %>
- <%= ts("Banned?") %>
- <%= ts("Created") %>
- <%= ts("Updated") %>
- <%= ts("Actions") %>
+ <%= t(".table.headings.name") %>
+ <%= t(".table.headings.token") %>
+ <%= t(".table.headings.banned") %>
+ <%= t(".table.headings.created") %>
+ <%= t(".table.headings.updated") %>
+ <%= t(".table.headings.actions") %>
<%= api_key.updated_at %>
diff --git a/config/locales/views/en.yml b/config/locales/views/en.yml
index 3c71d374377..94402cbee30 100644
--- a/config/locales/views/en.yml
+++ b/config/locales/views/en.yml
@@ -178,6 +178,31 @@ en:
required: Required when adding or removing a warning or suspension to an account.
submit: Update
heading: Record Warnings, Suspensions, or Notes
+ api:
+ edit:
+ page_title: Edit API Token
+ index:
+ actions:
+ find: Find
+ page_heading: API Tokens
+ page_title: API Tokens
+ search_box:
+ label: Name
+ search_by_name: Search for an API token by name
+ table:
+ actions:
+ edit: Edit
+ caption: API Tokens
+ headings:
+ actions: Actions
+ banned: Banned?
+ created: Created
+ name: Name
+ token: Token
+ updated: Updated
+ summary: Existing API tokens along with the dates they were created and updated and options for editing them.
+ new:
+ page_title: New API Token
banners:
index:
actions:
@@ -218,7 +243,7 @@ en:
header:
nav:
activities: Activities
- api_tokens: Manage API Tokens
+ api_tokens: API Tokens
banned_emails: Banned Emails
banners: Banners
invitations:
diff --git a/spec/controllers/admin/api_controller_spec.rb b/spec/controllers/admin/api_controller_spec.rb
index 5701f9b881b..ae29f9c5470 100644
--- a/spec/controllers/admin/api_controller_spec.rb
+++ b/spec/controllers/admin/api_controller_spec.rb
@@ -29,38 +29,72 @@
end
context "where admin is logged in" do
- render_views
- let(:admin) { FactoryBot.create(:admin) }
+ context "when admin does not have correct authorization" do
+ context "when admin has no role" do
+ let(:admin) { create(:admin, roles: []) }
- before do
- fake_login_admin(admin)
- end
+ before do
+ fake_login_admin(admin)
+ end
- let(:api_key_prefixes) { %w(a b c) }
- let!(:api_keys) do
- api_key_prefixes.each do |p|
- FactoryBot.create(:api_key, name: "#{p}_key")
+ it "redirects with error" do
+ get :index, params: params
+
+ it_redirects_to_with_error(root_path, "Sorry, only an authorized admin can access the page you were trying to reach.")
+ end
+ end
+
+ (Admin::VALID_ROLES - %w[superadmin]).each do |role|
+ context "when admin has #{role} role" do
+ let(:admin) { create(:admin, roles: [role]) }
+
+ before do
+ fake_login_admin(admin)
+ end
+
+ it "redirects with error" do
+ get :index, params: params
+
+ it_redirects_to_with_error(root_path, "Sorry, only an authorized admin can access the page you were trying to reach.")
+ end
+ end
end
end
- context "where no query params are set" do
- it "returns a successful response with all api keys" do
- get :index, params: params
- expect(response).to have_http_status(:success)
+ context "when admin is authorized with the superadmin role" do
+ render_views
+ let(:admin) { create(:admin, roles: ["superadmin"]) }
+
+ before do
+ fake_login_admin(admin)
+ end
+
+ let(:api_key_prefixes) { %w(a b c) }
+ let!(:api_keys) do
api_key_prefixes.each do |p|
- expect(response.body).to include("#{p}_key")
+ FactoryBot.create(:api_key, name: "#{p}_key")
end
end
- end
-
- context "where query params are set" do
- let(:params) { { query: "a_key" } }
- it "returns a successful response with a filtered list of api keys" do
- get :index, params: params
- expect(response).to have_http_status(:success)
- expect(response.body).to include("a_key")
- expect(response.body).to_not include("b_key")
- expect(response.body).to_not include("c_key")
+
+ context "where no query params are set" do
+ it "returns a successful response with all api keys" do
+ get :index, params: params
+ expect(response).to have_http_status(:success)
+ api_key_prefixes.each do |p|
+ expect(response.body).to include("#{p}_key")
+ end
+ end
+ end
+
+ context "where query params are set" do
+ let(:params) { { query: "a_key" } }
+ it "returns a successful response with a filtered list of api keys" do
+ get :index, params: params
+ expect(response).to have_http_status(:success)
+ expect(response.body).to include("a_key")
+ expect(response.body).to_not include("b_key")
+ expect(response.body).to_not include("c_key")
+ end
end
end
end
@@ -68,70 +102,138 @@
describe "GET #new" do
context "where an admin is logged in" do
- let(:admin) { FactoryBot.create(:admin) }
+ context "when admin does not have correct authorization" do
+ context "when admin has no role" do
+ let(:admin) { create(:admin, roles: []) }
- before do
- fake_login_admin(admin)
+ before do
+ fake_login_admin(admin)
+ end
+
+ it "redirects with error" do
+ get :new
+
+ it_redirects_to_with_error(root_path, "Sorry, only an authorized admin can access the page you were trying to reach.")
+ end
+ end
+
+ (Admin::VALID_ROLES - %w[superadmin]).each do |role|
+ context "when admin has #{role} role" do
+ let(:admin) { create(:admin, roles: [role]) }
+
+ before do
+ fake_login_admin(admin)
+ end
+
+ it "redirects with error" do
+ get :new
+
+ it_redirects_to_with_error(root_path, "Sorry, only an authorized admin can access the page you were trying to reach.")
+ end
+ end
+ end
end
- it "responds with the new api key form" do
- get :new
- expect(response).to have_http_status(:success)
- assert_template :new
+
+ context "when admin is authorized with the superadmin role" do
+ let(:admin) { create(:admin, roles: ["superadmin"]) }
+
+ before do
+ fake_login_admin(admin)
+ end
+ it "responds with the new api key form" do
+ get :new
+ expect(response).to have_http_status(:success)
+ assert_template :new
+ end
end
end
end
describe "POST #create" do
context "where an admin is logged in" do
- let(:admin) { FactoryBot.create(:admin) }
- let(:params) { {} }
+ context "when admin does not have correct authorization" do
+ context "when admin has no role" do
+ let(:admin) { create(:admin, roles: []) }
- before do
- fake_login_admin(admin)
- end
-
- context "with an api key param" do
- let(:api_key_name) { "api_key" }
- let(:api_key_params) { { name: api_key_name } }
- let(:params) { { api_key: api_key_params } }
+ before do
+ fake_login_admin(admin)
+ end
- it "redirects to the homepage and notifies of the success" do
- post :create, params: params
- expect(ApiKey.where(name: api_key_name)).to_not be_empty
- it_redirects_to_with_notice(admin_api_index_path, "New token successfully created")
+ it "redirects with error" do
+ post :create
+
+ it_redirects_to_with_error(root_path, "Sorry, only an authorized admin can access the page you were trying to reach.")
+ end
end
- end
-
- context "without an api key param" do
- it "shows the new api view" do
- post :create, params: params
- expect(response).to have_http_status(:success)
- assert_template :new
+
+ (Admin::VALID_ROLES - %w[superadmin]).each do |role|
+ context "when admin has #{role} role" do
+ let(:admin) { create(:admin, roles: [role]) }
+
+ before do
+ fake_login_admin(admin)
+ end
+
+ it "redirects with error" do
+ post :create
+
+ it_redirects_to_with_error(root_path, "Sorry, only an authorized admin can access the page you were trying to reach.")
+ end
+ end
end
end
- context "the save was unsuccessful" do
- let(:api_key_name) { "api_key" }
- let(:api_key_params) { { name: api_key_name } }
- let(:params) { { api_key: api_key_params } }
+ context "when admin is authorized with the superadmin role" do
+ let(:admin) { create(:admin, roles: ["superadmin"]) }
+ let(:params) { {} }
before do
- allow_any_instance_of(ApiKey).to receive(:save).and_return(false)
+ fake_login_admin(admin)
end
- it "shows the new api view" do
- post :create, params: params
- expect(ApiKey.where(name: api_key_name)).to be_empty
- assert_template :new
+ context "with an api key param" do
+ let(:api_key_name) { "api_key" }
+ let(:api_key_params) { { name: api_key_name } }
+ let(:params) { { api_key: api_key_params } }
+
+ it "redirects to the homepage and notifies of the success" do
+ post :create, params: params
+ expect(ApiKey.where(name: api_key_name)).to_not be_empty
+ it_redirects_to_with_notice(admin_api_index_path, "New token successfully created")
+ end
+ end
+
+ context "without an api key param" do
+ it "shows the new api view" do
+ post :create, params: params
+ expect(response).to have_http_status(:success)
+ assert_template :new
+ end
end
- end
- context "cancel_button is present" do
- let(:params) { { cancel_button: "Cancel" } }
+ context "the save was unsuccessful" do
+ let(:api_key_name) { "api_key" }
+ let(:api_key_params) { { name: api_key_name } }
+ let(:params) { { api_key: api_key_params } }
- it "redirects to index" do
- post :create, params: params
- it_redirects_to admin_api_index_path
+ before do
+ allow_any_instance_of(ApiKey).to receive(:save).and_return(false)
+ end
+
+ it "shows the new api view" do
+ post :create, params: params
+ expect(ApiKey.where(name: api_key_name)).to be_empty
+ assert_template :new
+ end
+ end
+
+ context "cancel_button is present" do
+ let(:params) { { cancel_button: "Cancel" } }
+
+ it "redirects to index" do
+ post :create, params: params
+ it_redirects_to admin_api_index_path
+ end
end
end
end
@@ -139,27 +241,64 @@
describe "GET #edit" do
context "where an admin is logged in" do
- let(:admin) { FactoryBot.create(:admin) }
+ context "when admin does not have correct authorization" do
+ let(:api_key_id) { 123 }
+ let!(:api_key) { FactoryBot.create(:api_key, id: api_key_id) }
- before do
- fake_login_admin(admin)
- end
+ context "when admin has no role" do
+ let(:admin) { create(:admin, roles: []) }
- context "where the api key exists" do
- render_views
- let!(:api_key) { FactoryBot.create(:api_key, name: "api_key") }
+ before do
+ fake_login_admin(admin)
+ end
- it "populates the form with the api key" do
- get :edit, params: { id: api_key.id }
- expect(response).to have_http_status(:success)
- expect(response.body).to include(api_key.name)
+ it "redirects with error" do
+ get :edit, params: { id: api_key_id }
+
+ it_redirects_to_with_error(root_path, "Sorry, only an authorized admin can access the page you were trying to reach.")
+ end
+ end
+
+ (Admin::VALID_ROLES - %w[superadmin]).each do |role|
+ context "when admin has #{role} role" do
+ let(:admin) { create(:admin, roles: [role]) }
+
+ before do
+ fake_login_admin(admin)
+ end
+
+ it "redirects with error" do
+ get :edit, params: { id: api_key_id }
+
+ it_redirects_to_with_error(root_path, "Sorry, only an authorized admin can access the page you were trying to reach.")
+ end
+ end
end
end
- context "where the api key can't be found" do
- it "raises an error" do
- assert_raises ActiveRecord::RecordNotFound do
- get :edit, params: { id: 123 }
+ context "when admin is authorized with the superadmin role" do
+ let(:admin) { create(:admin, roles: ["superadmin"]) }
+
+ before do
+ fake_login_admin(admin)
+ end
+
+ context "where the api key exists" do
+ render_views
+ let!(:api_key) { FactoryBot.create(:api_key, name: "api_key") }
+
+ it "populates the form with the api key" do
+ get :edit, params: { id: api_key.id }
+ expect(response).to have_http_status(:success)
+ expect(response.body).to include(api_key.name)
+ end
+ end
+
+ context "where the api key can't be found" do
+ it "raises an error" do
+ assert_raises ActiveRecord::RecordNotFound do
+ get :edit, params: { id: 123 }
+ end
end
end
end
@@ -168,59 +307,96 @@
describe "POST #update" do
context "where an admin is logged in" do
- let(:admin) { FactoryBot.create(:admin) }
+ context "when admin does not have correct authorization" do
+ let(:api_key_id) { 123 }
+ let!(:api_key) { FactoryBot.create(:api_key, id: api_key_id) }
+
+ context "when admin has no role" do
+ let(:admin) { create(:admin, roles: []) }
- before do
- fake_login_admin(admin)
+ before do
+ fake_login_admin(admin)
+ end
+
+ it "redirects with error" do
+ post :update, params: { id: api_key_id, api_key: { name: "new_name" } }
+
+ it_redirects_to_with_error(root_path, "Sorry, only an authorized admin can access the page you were trying to reach.")
+ end
+ end
+
+ (Admin::VALID_ROLES - %w[superadmin]).each do |role|
+ context "when admin has #{role} role" do
+ let(:admin) { create(:admin, roles: [role]) }
+
+ before do
+ fake_login_admin(admin)
+ end
+
+ it "redirects with error" do
+ post :update, params: { id: api_key_id, api_key: { name: "new_name" } }
+
+ it_redirects_to_with_error(root_path, "Sorry, only an authorized admin can access the page you were trying to reach.")
+ end
+ end
+ end
end
- context "where the api key exists" do
- let(:api_key) { FactoryBot.create(:api_key) }
- let(:new_name) { "new_name" }
- let(:params) do
- {
- id: api_key.id,
- api_key: { name: new_name }
- }
+ context "when admin is authorized with the superadmin role" do
+ let(:admin) { create(:admin, roles: ["superadmin"]) }
+
+ before do
+ fake_login_admin(admin)
end
- context "where the update is successful" do
- it "updates the api key and redirects to index" do
- expect(ApiKey.where(name: new_name)).to be_empty
- post :update, params: params
- expect(ApiKey.where(name: new_name)).to_not be_empty
- it_redirects_to_with_notice(admin_api_index_path, "Access token was successfully updated")
+ context "where the api key exists" do
+ let(:api_key) { FactoryBot.create(:api_key) }
+ let(:new_name) { "new_name" }
+ let(:params) do
+ {
+ id: api_key.id,
+ api_key: { name: new_name }
+ }
end
- end
- context "where the update is unsuccessful" do
- before do
- allow_any_instance_of(ApiKey).to receive(:update).and_return(false)
+ context "where the update is successful" do
+ it "updates the api key and redirects to index" do
+ expect(ApiKey.where(name: new_name)).to be_empty
+ post :update, params: params
+ expect(ApiKey.where(name: new_name)).to_not be_empty
+ it_redirects_to_with_notice(admin_api_index_path, "Access token was successfully updated")
+ end
end
- it "shows the edit view" do
- post :update, params: { id: api_key.id, api_key: { name: "new_name" } }
- expect(ApiKey.where(name: "new_name")).to be_empty
- assert_template :edit
+ context "where the update is unsuccessful" do
+ before do
+ allow_any_instance_of(ApiKey).to receive(:update).and_return(false)
+ end
+
+ it "shows the edit view" do
+ post :update, params: { id: api_key.id, api_key: { name: "new_name" } }
+ expect(ApiKey.where(name: "new_name")).to be_empty
+ assert_template :edit
+ end
end
end
- end
- context "where the api key doesn't exist" do
- it "raises an error" do
- assert_raises ActiveRecord::RecordNotFound do
- post :update, params: { id: 123, api_key: { name: "new_name" } }
+ context "where the api key doesn't exist" do
+ it "raises an error" do
+ assert_raises ActiveRecord::RecordNotFound do
+ post :update, params: { id: 123, api_key: { name: "new_name" } }
+ end
end
end
- end
- context "cancel_button is true" do
- let(:api_key_id) { 123 }
- let!(:api_key) { FactoryBot.create(:api_key, id: api_key_id) }
+ context "cancel_button is true" do
+ let(:api_key_id) { 123 }
+ let!(:api_key) { FactoryBot.create(:api_key, id: api_key_id) }
- it "redirects to index" do
- post :update, params: { id: api_key_id, cancel_button: "Cancel" }
- it_redirects_to admin_api_index_path
+ it "redirects to index" do
+ post :update, params: { id: api_key_id, cancel_button: "Cancel" }
+ it_redirects_to admin_api_index_path
+ end
end
end
end
@@ -228,27 +404,64 @@
describe "POST #destroy" do
context "where an admin is logged in" do
- let(:admin) { FactoryBot.create(:admin) }
-
- before do
- fake_login_admin(admin)
- end
-
- context "where the api key exists" do
+ context "when admin does not have correct authorization" do
let(:api_key_id) { 123 }
let!(:api_key) { FactoryBot.create(:api_key, id: api_key_id) }
- it "destroys the api key, then redirects to edit" do
- post :destroy, params: { id: api_key_id }
- expect(ApiKey.where(id: api_key_id)).to be_empty
- expect(response).to redirect_to admin_api_path
+ context "when admin has no role" do
+ let(:admin) { create(:admin, roles: []) }
+
+ before do
+ fake_login_admin(admin)
+ end
+
+ it "redirects with error" do
+ post :destroy, params: { id: api_key_id }
+
+ it_redirects_to_with_error(root_path, "Sorry, only an authorized admin can access the page you were trying to reach.")
+ end
+ end
+
+ (Admin::VALID_ROLES - %w[superadmin]).each do |role|
+ context "when admin has #{role} role" do
+ let(:admin) { create(:admin, roles: [role]) }
+
+ before do
+ fake_login_admin(admin)
+ end
+
+ it "redirects with error" do
+ post :destroy, params: { id: api_key_id }
+
+ it_redirects_to_with_error(root_path, "Sorry, only an authorized admin can access the page you were trying to reach.")
+ end
+ end
end
end
- context "where the api key doesn't exist" do
- it "raises an error" do
- assert_raises ActiveRecord::RecordNotFound do
- post :destroy, params: { id: 123 }
+ context "when admin is authorized with the superadmin role" do
+ let(:admin) { create(:admin, roles: ["superadmin"]) }
+
+ before do
+ fake_login_admin(admin)
+ end
+
+ context "where the api key exists" do
+ let(:api_key_id) { 123 }
+ let!(:api_key) { FactoryBot.create(:api_key, id: api_key_id) }
+
+ it "destroys the api key, then redirects to edit" do
+ post :destroy, params: { id: api_key_id }
+ expect(ApiKey.where(id: api_key_id)).to be_empty
+ expect(response).to redirect_to admin_api_path
+ end
+ end
+
+ context "where the api key doesn't exist" do
+ it "raises an error" do
+ assert_raises ActiveRecord::RecordNotFound do
+ post :destroy, params: { id: 123 }
+ end
end
end
end
From 61a4f52873396c769bfd986f58162319775e66d9 Mon Sep 17 00:00:00 2001
From: EchoEkhi
-
+ <%= t("mailer.general.signature.app_short_name") %>
+ <%= t(".works", count: works.size) %>
+ <%= render "works/work_abbreviated_list", works: works %>
+ <%= will_paginate(works, param_name: "works_page", params: { anchor: "works-summary" }) %>
+ <%= ts("Delete Spammer Creations") %>
+<%= t(".page_heading") %>
<%= form_tag destroy_user_creations_admin_user_path(@user), method: :post, class: "simple destroy" do %>
<%= ts("Works")%> (<%= @works.size %>)
- <%= render "works/work_abbreviated_list", works: @works %>
- <%= will_paginate(@works, param_name: 'works_page') %>
- <%= ts("Comments")%> (<%= @comments.size %>)
- <%= render "comments/comment_abbreviated_list", comments: @comments %>
- <%= will_paginate(@comments, :param_name => 'comments_page') %>
- <%= t(".page_heading", user: @user.login) %>
+
+
+
+
+
+
+
+
+ <% if @works.empty? && @comments.empty? %>
+
<% comments.each do |comment| %>
<% if @user == current_user %>
-
diff --git a/config/locales/helpers/en.yml b/config/locales/helpers/en.yml
index 0ce91162447..e19b01e4de4 100644
--- a/config/locales/helpers/en.yml
+++ b/config/locales/helpers/en.yml
@@ -20,6 +20,12 @@ en:
user:
bookmark: Bookmarker approval status
work: Creator approval status
+ comments_helper:
+ comment_link_with_commentable_name:
+ on_admin_post_html: Comment on the news post %{title}
+ on_tag_html: Comment on the tag %{name}
+ on_unknown: Comment on unknown item
+ on_work_html: Comment on the work %{title}
users_helper:
log:
ban: Suspended Permanently
diff --git a/config/locales/views/en.yml b/config/locales/views/en.yml
index 94402cbee30..b334dd7ec2b 100644
--- a/config/locales/views/en.yml
+++ b/config/locales/views/en.yml
@@ -115,6 +115,16 @@ en:
series: Make Series Visible
work: Make Work Visible
admin_users:
+ confirm_delete_user_creations:
+ caution_html: Are you sure you want to delete all the works and comments created by this user, along with their %{bookmarks} bookmarks, %{series} series, and %{collections} collections? This cannot be undone.
+ confirm: Are you sure? Remember this will destroy ALL these objects!
+ page_heading: Delete Spammer Creations
+ submit: Yes, Delete All Spammer Creations
+ creations:
+ admin_user: User Administration
+ no_creations: This user has no works or comments.
+ page_heading: Works and Comments by %{user}
+ page_title: "%{login} - User Creations"
history:
heading: User History
table:
@@ -153,10 +163,10 @@ en:
other: 'Roles:'
navigation:
activate: Activate
+ creations: Creations
invitations:
add: Add Invitations
manage: Manage Invitations
- profile: Profile
roles: Manage Roles
troubleshoot: Troubleshoot
note: To fix common errors with this user's Subscriptions and Stats pages, and to reindex their works and bookmarks, choose "Troubleshoot."
@@ -178,6 +188,9 @@ en:
required: Required when adding or removing a warning or suspension to an account.
submit: Update
heading: Record Warnings, Suspensions, or Notes
+ user_creations_summary:
+ comments: Comments (%{count})
+ works: Works (%{count})
api:
edit:
page_title: Edit API Token
@@ -934,6 +947,11 @@ en:
submit: Save
edit:
browser_title: Edit Profile
+ header_navigation:
+ admin_user: User Administration
+ edit_multiple: Edit Works
+ invitations: Invitations
+ new_work: Post New
registrations:
new:
cancel: Cancel
diff --git a/config/routes.rb b/config/routes.rb
index d67b8dab288..35f7e054bdd 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -204,6 +204,7 @@
post :destroy_user_creations
post :activate
get :check_user
+ get :creations
end
collection do
get :bulk_search
diff --git a/features/admins/users/admin_abuse_users.feature b/features/admins/users/admin_abuse_users.feature
index 781002d215e..a1aa93692fb 100644
--- a/features/admins/users/admin_abuse_users.feature
+++ b/features/admins/users/admin_abuse_users.feature
@@ -163,6 +163,7 @@ Feature: Admin Abuse actions
And I press "Update"
Then I should see "permanently suspended"
And the user "Spamster" should be permanently banned
+ And the page should have a dashboard sidebar
And I should see "Are you sure you want to delete"
And I should see "1 bookmarks"
And I should see "1 collections"
diff --git a/features/admins/users/admin_manage_users.feature b/features/admins/users/admin_manage_users.feature
index 329ba6d995d..0e6d01a1b2e 100644
--- a/features/admins/users/admin_manage_users.feature
+++ b/features/admins/users/admin_manage_users.feature
@@ -84,3 +84,27 @@ Feature: Admin Actions to manage users
And I should see "Invitation: Created without invitation"
When I go to the user administration page for "user2"
Then I should see the invitation id for the user "user2"
+
+ Scenario: An admin can access a user's creations from their administration page
+ Given the user "lurker" exists and is activated
+ And I am logged in as "troll"
+ And I post the work "Creepy Gift"
+ And I post the comment "Neener" on the work "Creepy Gift"
+ When I am logged in as a "support" admin
+ And I go to the user administration page for "lurker"
+ Then the page should have a dashboard sidebar
+ And I should not see "Creations"
+ When I am logged in as a "policy_and_abuse" admin
+ And I go to the user administration page for "lurker"
+ And I follow "Creations"
+ Then I should see "Works and Comments by lurker"
+ And I should see "This user has no works or comments."
+ And the page should have a dashboard sidebar
+ When I go to the user administration page for "troll"
+ And I follow "Creations"
+ Then I should see "Works and Comments by troll"
+ And I should see "Works (1)" within "#works-summary"
+ And I should see "Creepy Gift" within "#works-summary"
+ And I should see "Comments (1)" within "#comments-summary"
+ And I should see "Comment on the work Creepy Gift" within "#comments-summary"
+ And I should see "<%= t(".works", count: works.size) %>
+ <%= search_header(@works, nil, "Work") %>
<%= render "works/work_abbreviated_list", works: works %>
<%= will_paginate(works, param_name: "works_page", params: { anchor: "works-summary" }) %>
<%= t(".comments", count: comments.size) %>
+ <%= search_header(@comments, nil, "Comment") %>
<%= render "comments/comment_abbreviated_list", comments: comments %>
<%= will_paginate(comments, param_name: "comments_page", params: { anchor: "comments-summary" }) %>
+
- <% if @works.empty? && @comments.empty? %>
+ <% if @user.works.empty? && @user.comments.empty? %>
+
<%= t(".navigation.admin.landmark") %>
-
<%= t(".navigation.admin.landmark") %>
<% if policy(@admin_post).edit? %>
From 50832406ae6595861d16d6b3c3fff04a68f16190 Mon Sep 17 00:00:00 2001
From: Bilka
- <%= params[:type].blank? ? ts('My Subscriptions') :
- ts('My %{type} Subscriptions', type: params[:type].to_s.singularize.titleize)
- %>
+ <% if @subscribable_type %>
+ <%= t(".page_heading.#{@subscribable_type}") %>
+ <% else %>
+ <%= t(".page_heading.all") %>
+ <% end %>
-<%= ts('Navigation') %>
+<%= t("a11y.navigation") %>
@@ -34,28 +37,31 @@
<%= will_paginate @subscriptions %>
-<%= ts('List of Subscriptions') %>
+<%= t(".heading.landmark.list") %>
<% @subscriptions.each do |subscription| %>
<%= will_paginate @subscriptions %>
-
\ No newline at end of file
+
diff --git a/config/locales/models/en.yml b/config/locales/models/en.yml
index ea6f31f8b19..79c8693ebc5 100644
--- a/config/locales/models/en.yml
+++ b/config/locales/models/en.yml
@@ -236,3 +236,5 @@ en:
closed_ticket: must not be closed.
invalid_department: must be in your department.
required: must exist and not be spam.
+ subscriptions:
+ deleted: Deleted item
diff --git a/config/locales/views/en.yml b/config/locales/views/en.yml
index 0ed243ec9e4..17ab26c4965 100644
--- a/config/locales/views/en.yml
+++ b/config/locales/views/en.yml
@@ -852,6 +852,25 @@ en:
skins:
confirm_delete:
confirm_html: Are you sure you want to delete the skin "%{skin_title}"?
+ subscriptions:
+ index:
+ button_html: Unsubscribe from %{name}
+ byline: by %{creators}
+ heading:
+ landmark:
+ list: List of Subscriptions
+ navigation:
+ all: All Subscriptions
+ series: Series Subscriptions
+ user: User Subscriptions
+ work: Work Subscriptions
+ page_heading:
+ all: My Subscriptions
+ series: My Series Subscriptions
+ users: My User Subscriptions
+ works: My Work Subscriptions
+ series: "(Series)"
+ work: "(Work)"
tag_wranglers:
show:
last_wrangled_html: "%{wrangler_login} last wrangled at %{time}."
diff --git a/spec/controllers/subscriptions_controller_spec.rb b/spec/controllers/subscriptions_controller_spec.rb
new file mode 100644
index 00000000000..9d1cdae2750
--- /dev/null
+++ b/spec/controllers/subscriptions_controller_spec.rb
@@ -0,0 +1,79 @@
+require "spec_helper"
+
+describe SubscriptionsController do
+ include LoginMacros
+ include RedirectExpectationHelper
+
+ let(:user) { create(:user) }
+
+ describe "GET #index" do
+ let(:author) { create(:user) }
+ let(:work) { create(:work) }
+ let(:series) { create(:series) }
+ let!(:sub_series) { create(:subscription, user: user, subscribable: series) }
+ let!(:sub_work) { create(:subscription, user: user, subscribable_type: "Work", subscribable_id: work.id) }
+ let!(:sub_user) { create(:subscription, user: user, subscribable_type: "User", subscribable_id: author.id) }
+
+ it "redirects to login when not logged in" do
+ get :index, params: { user_id: user.login }
+ it_redirects_to_with_error(new_user_session_path,
+ "Sorry, you don't have permission to access the page you were trying to reach. Please log in.")
+ end
+
+ context "when logged in" do
+ before { fake_login_known_user(user) }
+
+ it "renders all subscriptions" do
+ get :index, params: { user_id: user.login }
+ expect(response).to render_template("index")
+ expect(assigns(:subscriptions)).to contain_exactly(sub_series, sub_work, sub_user)
+ end
+
+ context "with invalid subscriptions" do
+ let!(:subscription) { create(:subscription, user: user) }
+
+ before do
+ Subscription.update_all(subscribable_id: -1)
+ end
+
+ it "renders all subscriptions" do
+ get :index, params: { user_id: user.login }
+ expect(response).to render_template("index")
+
+ bad_sub = assigns(:subscriptions)[0]
+ expect(bad_sub.subscribable_id).to eq(-1)
+ expect(bad_sub.name).to eq("Deleted item")
+ end
+
+ it "allows deletion of invalid subscriptions" do
+ get :index, params: { user_id: user.login }
+ sub_id = assigns(:subscriptions)[0].id
+ delete :destroy, params: { user_id: user.login, id: sub_id }
+ it_redirects_to_with_notice(user_subscriptions_path(user), "You have successfully unsubscribed from Deleted item.")
+ end
+ end
+
+ context "with valid subscription types in params" do
+ %w[series works users].each do |sub_type|
+ it "renders #{sub_type} subscriptions only" do
+ get :index, params: { user_id: user.login, type: sub_type }
+
+ expect(response).to render_template("index")
+ expect(assigns(:subscribable_type)).to eq(sub_type)
+ expect(assigns(:subscriptions).count).to eq(1)
+ end
+ end
+ end
+
+ context "with invalid subscription type in params" do
+ it "renders all subscriptions" do
+ get :index, params: { user_id: user.login, type: "Invalid" }
+
+ expect(response).to render_template("index")
+ expect(assigns(:subscribable_type)).to be_nil
+ expect(assigns(:subscriptions)).to contain_exactly(sub_series, sub_work, sub_user)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/models/subscription_spec.rb b/spec/models/subscription_spec.rb
index f2b001be161..e2ee6ef2e79 100644
--- a/spec/models/subscription_spec.rb
+++ b/spec/models/subscription_spec.rb
@@ -2,13 +2,20 @@
describe Subscription do
let(:subscription) { build(:subscription) }
+ let(:work) { create(:work) }
+ let(:series) { create(:series) }
+ let(:user) { create(:user) }
context "to a work" do
before do
- subscription.subscribable = create(:work)
+ subscription.subscribable = work
subscription.save!
end
+ it "has a name" do
+ expect(subscription.name).to eq(work.title)
+ end
+
describe "when the work is destroyed" do
before do
subscription.subscribable.destroy
@@ -22,10 +29,14 @@
context "to a series" do
before do
- subscription.subscribable = create(:series)
+ subscription.subscribable = series
subscription.save!
end
+ it "has a name" do
+ expect(subscription.name).to eq(series.title)
+ end
+
describe "when the series is destroyed" do
before do
subscription.subscribable.destroy
@@ -39,10 +50,14 @@
context "to a user" do
before do
- subscription.subscribable = create(:user)
+ subscription.subscribable = user
subscription.save!
end
+ it "has a name" do
+ expect(subscription.name).to eq(user.login)
+ end
+
describe "when the user is destroyed" do
before do
subscription.subscribable.destroy
@@ -65,6 +80,10 @@
it "should be invalid" do
expect(subscription.valid?).to be_falsey
end
+
+ it "has a name" do
+ expect(subscription.name).to eq("Deleted item")
+ end
end
context "when subscribable is not a valid object to subscribe to" do
From 927ca659b4b4408c822aeb3c97ef7b9740b26b22 Mon Sep 17 00:00:00 2001
From: Bilka <%= ts("Comment Actions") %>
-
+
style="display:none;"<% end %>>
<% # The effect is "Frozen" replaces "Reply." We can't do that in the helper
# method for the reply link because that would prevent "Frozen" from
# appearing on the Unreviewed Comments page for works with moderated
@@ -9,7 +9,7 @@
<%= t(".comments", count: comments.size) %>
+ <%= render "comments/comment_abbreviated_list", comments: comments %> + <%= will_paginate(comments, param_name: "comments_page", params: { anchor: "comments-summary" }) %> +