diff --git a/.rubocop.yml b/.rubocop.yml index 3e0d86588b2..c7aba15a513 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -45,6 +45,7 @@ Lint/AmbiguousBlockAssociation: Exclude: # Exception for specs where we use change matchers: # https://github.com/rubocop-hq/rubocop/issues/4222 + - 'features/step_definitions/**/*.rb' - 'spec/**/*.rb' Lint/AmbiguousRegexpLiteral: diff --git a/app/controllers/pseuds_controller.rb b/app/controllers/pseuds_controller.rb index f71c4ddf8e3..37b1e2a818b 100644 --- a/app/controllers/pseuds_controller.rb +++ b/app/controllers/pseuds_controller.rb @@ -26,44 +26,40 @@ def index # GET /users/:user_id/pseuds/:id def show - if @user.blank? - raise ActiveRecord::RecordNotFound, "Couldn't find user '#{params[:user_id]}'" - end - @pseud = @user.pseuds.find_by(name: params[:id]) - unless @pseud - raise ActiveRecord::RecordNotFound, "Couldn't find pseud '#{params[:id]}'" - end + raise ActiveRecord::RecordNotFound, t(".could_not_find_user", username: params[:user_id]) if @user.blank? + + @pseud = @user.pseuds.find_by!(name: params[:id]) @page_subtitle = @pseud.name # very similar to show under users - if you change something here, change it there too - if !(logged_in? || logged_in_as_admin?) - visible_works = @pseud.works.visible_to_all - visible_series = @pseud.series.visible_to_all - visible_bookmarks = @pseud.bookmarks.visible_to_all - else + if logged_in? || logged_in_as_admin? visible_works = @pseud.works.visible_to_registered_user visible_series = @pseud.series.visible_to_registered_user visible_bookmarks = @pseud.bookmarks.visible_to_registered_user + else + visible_works = @pseud.works.visible_to_all + visible_series = @pseud.series.visible_to_all + visible_bookmarks = @pseud.bookmarks.visible_to_all end visible_works = visible_works.revealed.non_anon visible_series = visible_series.exclude_anonymous @fandoms = \ - Fandom.select("tags.*, count(DISTINCT works.id) as work_count"). - joins(:filtered_works).group("tags.id").merge(visible_works). - where(filter_taggings: { inherited: false }). - order('work_count DESC').load + Fandom.select("tags.*, count(DISTINCT works.id) as work_count") + .joins(:filtered_works).group("tags.id").merge(visible_works) + .where(filter_taggings: { inherited: false }) + .order("work_count DESC").load @works = visible_works.order("revised_at DESC").limit(ArchiveConfig.NUMBER_OF_ITEMS_VISIBLE_IN_DASHBOARD) @series = visible_series.order("updated_at DESC").limit(ArchiveConfig.NUMBER_OF_ITEMS_VISIBLE_IN_DASHBOARD) @bookmarks = visible_bookmarks.order("updated_at DESC").limit(ArchiveConfig.NUMBER_OF_ITEMS_VISIBLE_IN_DASHBOARD) - if current_user.respond_to?(:subscriptions) - @subscription = current_user.subscriptions.where(subscribable_id: @user.id, - subscribable_type: 'User').first || - current_user.subscriptions.build(subscribable: @user) - end + return unless current_user.respond_to?(:subscriptions) + + @subscription = current_user.subscriptions.where(subscribable_id: @user.id, + subscribable_type: "User").first || + current_user.subscriptions.build(subscribable: @user) end # GET /pseuds/new @@ -86,7 +82,7 @@ def create @pseud.user_id = @user.id old_default = @user.default_pseud if @pseud.save - flash[:notice] = ts('Pseud was successfully created.') + flash[:notice] = t(".successfully_created") if @pseud.is_default # if setting this one as default, unset the attribute of the current default pseud old_default.update_attribute(:is_default, false) @@ -96,8 +92,8 @@ def create render action: "new" end else - # user tried to add pseud he already has - flash[:error] = ts('You already have a pseud with that name.') + # user tried to add pseud they already have + flash[:error] = t(".already_have_pseud_with_name") render action: "new" end end @@ -115,12 +111,9 @@ def update AdminActivity.log_action(current_admin, @pseud, action: "edit pseud", summary: summary) end # if setting this one as default, unset the attribute of the current default pseud - if @pseud.is_default and not(default == @pseud) - # if setting this one as default, unset the attribute of the current active pseud - default.update_attribute(:is_default, false) - end - flash[:notice] = ts('Pseud was successfully updated.') - redirect_to([@user, @pseud]) + default.update_attribute(:is_default, false) if @pseud.is_default && default != @pseud + flash[:notice] = t(".successfully_updated") + redirect_to([@user, @pseud]) else render action: "edit" end @@ -131,24 +124,24 @@ def update def destroy @hide_dashboard = true if params[:cancel_button] - flash[:notice] = ts("The pseud was not deleted.") + flash[:notice] = t(".not_deleted") redirect_to(user_pseuds_path(@user)) && return end @pseud = @user.pseuds.find_by(name: params[:id]) if @pseud.is_default - flash[:error] = ts("You cannot delete your default pseudonym, sorry!") + flash[:error] = t(".cannot_delete_default") elsif @pseud.name == @user.login - flash[:error] = ts("You cannot delete the pseud matching your user name, sorry!") + flash[:error] = t(".cannot_delete_matching_username") elsif params[:bookmarks_action] == "transfer_bookmarks" @pseud.change_bookmarks_ownership @pseud.replace_me_with_default - flash[:notice] = ts("The pseud was successfully deleted.") + flash[:notice] = t(".successfully_deleted") elsif params[:bookmarks_action] == "delete_bookmarks" || @pseud.bookmarks.empty? @pseud.replace_me_with_default - flash[:notice] = ts("The pseud was successfully deleted.") + flash[:notice] = t(".successfully_deleted") else - render 'delete_preview' and return + render "delete_preview" and return end redirect_to(user_pseuds_path(@user)) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index b99c8581c55..84607950167 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -3,8 +3,8 @@ class UsersController < ApplicationController before_action :check_user_status, only: [:edit, :update, :change_username, :changed_username] before_action :load_user, except: [:activate, :delete_confirmation, :index] - before_action :check_ownership, except: [:activate, :delete_confirmation, :edit, :index, :show, :update] - before_action :check_ownership_or_admin, only: [:edit, :update] + before_action :check_ownership, except: [:activate, :change_username, :changed_username, :delete_confirmation, :edit, :index, :show, :update] + before_action :check_ownership_or_admin, only: [:change_username, :changed_username, :edit, :update] skip_before_action :store_location, only: [:end_first_login] def load_user @@ -48,6 +48,7 @@ def change_password end def change_username + authorize @user if logged_in_as_admin? @page_subtitle = t(".browser_title") end @@ -70,20 +71,27 @@ def changed_password end def changed_username - render(:change_username) && return unless params[:new_login].present? + authorize @user if logged_in_as_admin? + render(:change_username) && return if params[:new_login].blank? @new_login = params[:new_login] - unless @user.valid_password?(params[:password]) - flash[:error] = ts('Your password was incorrect') + unless logged_in_as_admin? || @user.valid_password?(params[:password]) + flash[:error] = t(".user.incorrect_password") render(:change_username) && return end @user.login = @new_login + @user.ticket_number = params[:ticket_number] if @user.save - flash[:notice] = ts('Your user name has been successfully updated.') - redirect_to @user + if logged_in_as_admin? + flash[:notice] = t(".admin.successfully_updated") + redirect_to admin_user_path(@user) + else + flash[:notice] = t(".user.successfully_updated") + redirect_to @user + end else @user.reload render :change_username diff --git a/app/models/concerns/justifiable.rb b/app/models/concerns/justifiable.rb index dea0c09d80c..206d66ddb7b 100644 --- a/app/models/concerns/justifiable.rb +++ b/app/models/concerns/justifiable.rb @@ -8,14 +8,14 @@ module Justifiable validates :ticket_number, presence: true, numericality: { only_integer: true }, - if: :enabled? + if: :justification_enabled? - validate :ticket_number_exists_in_tracker, if: :enabled? + validate :ticket_number_exists_in_tracker, if: :justification_enabled? end private - def enabled? + def justification_enabled? # Only require a ticket if the record has been changed by an admin. User.current_user.is_a?(Admin) && changed? end diff --git a/app/models/pseud.rb b/app/models/pseud.rb index ac298bc5fee..6e7bb327029 100644 --- a/app/models/pseud.rb +++ b/app/models/pseud.rb @@ -192,7 +192,7 @@ def self.parse_byline(byline) # Parse a string of the "pseud.name (user.login)" format into a list of # pseuds. Usually this will be just one pseud, but if the byline is of the - # form "pseud.name" with no parenthesized user name, it'll look for any pseud + # form "pseud.name" with no parenthesized username, it'll look for any pseud # with that name. def self.parse_byline_ambiguous(byline) pseud_name, login = split_byline(byline) diff --git a/app/models/user.rb b/app/models/user.rb index 47c6c6b3d04..52eed50bdd7 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,5 +1,6 @@ class User < ApplicationRecord audited redacted: [:encrypted_password, :password_salt] + include Justifiable include WorksOwner include PasswordResetsLimitable include UserLoggable @@ -90,7 +91,7 @@ class User < ApplicationRecord before_update :add_renamed_at, if: :will_save_change_to_login? after_update :update_pseud_name after_update :send_wrangler_username_change_notification, if: :is_tag_wrangler? - after_update :log_change_if_login_was_edited + after_update :log_change_if_login_was_edited, if: :saved_change_to_login? after_update :log_email_change, if: :saved_change_to_email? after_commit :reindex_user_creations_after_rename @@ -198,6 +199,7 @@ def unread_inbox_comments_count uniqueness: true, not_forbidden_name: { if: :will_save_change_to_login? } validate :username_is_not_recently_changed, if: :will_save_change_to_login? + validate :admin_username_generic, if: :will_save_change_to_login? # allow nil so can save existing users validates_length_of :password, @@ -525,6 +527,12 @@ def reindex_user_creations private + # Override the default Justifiable enabled check, because we only need to justify + # username changes at the moment. + def justification_enabled? + User.current_user.is_a?(Admin) && login_changed? + end + # Create and/or return a user account for holding orphaned works def self.fetch_orphan_account orphan_account = User.find_or_create_by(login: "orphan_account") @@ -564,11 +572,23 @@ def reindex_user_creations_after_rename end def add_renamed_at + return if User.current_user.is_a?(Admin) + self.renamed_at = Time.current end def log_change_if_login_was_edited - create_log_item(action: ArchiveConfig.ACTION_RENAME, note: "Old Username: #{login_before_last_save}; New Username: #{login}") if saved_change_to_login? + current_admin = User.current_user if User.current_user.is_a?(Admin) + options = { + action: ArchiveConfig.ACTION_RENAME, + admin: current_admin + } + options[:note] = if current_admin + "Old Username: #{login_before_last_save}, New Username: #{login}, Changed by: #{current_admin.login}, Ticket ID: ##{ticket_number}" + else + "Old Username: #{login_before_last_save}; New Username: #{login}" + end + create_log_item(options) end def send_wrangler_username_change_notification @@ -592,6 +612,8 @@ def remove_stale_from_autocomplete end def username_is_not_recently_changed + return if User.current_user.is_a?(Admin) + change_interval_days = ArchiveConfig.USER_RENAME_LIMIT_DAYS return unless renamed_at && change_interval_days.days.ago <= renamed_at @@ -601,6 +623,12 @@ def username_is_not_recently_changed renamed_at: I18n.l(renamed_at, format: :long)) end + def admin_username_generic + return unless User.current_user.is_a?(Admin) + + errors.add(:login, :admin_must_use_default) unless login == "user#{id}" + end + # Extra callback to make sure readings are deleted in an order consistent # with the ReadingsJob. # diff --git a/app/policies/user_policy.rb b/app/policies/user_policy.rb index 614196a67fb..2526585c48e 100644 --- a/app/policies/user_policy.rb +++ b/app/policies/user_policy.rb @@ -6,6 +6,9 @@ class UserPolicy < ApplicationPolicy # This is further restricted using ALLOWED_ATTRIBUTES_BY_ROLES. MANAGE_ROLES = %w[superadmin legal policy_and_abuse open_doors support tag_wrangling].freeze + # Roles that are allowed to set a generic username for users. + CHANGE_USERNAME_ROLES = %w[superadmin policy_and_abuse].freeze + # Roles that allow updating the Fannish Next Of Kin of a user. MANAGE_NEXT_OF_KIN_ROLES = %w[superadmin policy_and_abuse support].freeze @@ -18,8 +21,8 @@ class UserPolicy < ApplicationPolicy # Define which roles can update which attributes. ALLOWED_ATTRIBUTES_BY_ROLES = { "open_doors" => [roles: []], - "policy_and_abuse" => [:email, roles: []], - "superadmin" => [:email, roles: []], + "policy_and_abuse" => [:email, { roles: [] }], + "superadmin" => [:email, { roles: [] }], "support" => %i[email], "tag_wrangling" => [roles: []] }.freeze @@ -48,6 +51,10 @@ def can_access_creation_summary? user_has_roles?(REVIEW_CREATIONS_ROLES) end + def change_username? + user_has_roles?(CHANGE_USERNAME_ROLES) + end + def permitted_attributes ALLOWED_ATTRIBUTES_BY_ROLES.values_at(*user.roles).compact.flatten end @@ -60,6 +67,7 @@ def can_edit_user_role?(role) alias bulk_search? can_manage_users? alias show? can_manage_users? alias update? can_manage_users? + alias changed_username? change_username? alias update_next_of_kin? can_manage_next_of_kin? diff --git a/app/views/admin/admin_invitations/find.html.erb b/app/views/admin/admin_invitations/find.html.erb index 5d426feadfc..80ad1c0115a 100644 --- a/app/views/admin/admin_invitations/find.html.erb +++ b/app/views/admin/admin_invitations/find.html.erb @@ -1,30 +1,35 @@ -

<%h= 'Track invitations' %>

+

<%= t(".page_heading") %>

-<%= form_tag url_for(:controller => 'admin/admin_invitations', :action => 'find'), :method => :get do %> +<%= form_tag url_for(controller: "admin/admin_invitations", action: "find"), method: :get do %>
-
<%= label_tag "invitation[user_name]", t(".user_name") %>:
-
<%= text_field_tag "invitation[user_name]", params[:invitation][:user_name] %>
-
<%= label_tag "invitation[token]", t(".token") %>:
-
<%= text_field_tag "invitation[token]", params[:invitation][:token] %>
-
<%= label_tag "invitee_email", t(".email") %>:
-
<%= text_field_tag "invitation[invitee_email]", params[:invitation][:invitee_email], id: "invitee_email" %>
+
<%= label_tag "invitation[user_name]", t(".username") %>
+
<%= text_field_tag "invitation[user_name]", params[:invitation][:user_name], autocomplete: "on" %>
+
<%= label_tag "invitation[token]", t(".token") %>
+
<%= text_field_tag "invitation[token]", params[:invitation][:token], autocomplete: "on" %>
+
<%= label_tag "invitee_email", t(".email") %>
+
+ <%= text_field_tag "invitation[invitee_email]", + params[:invitation][:invitee_email], + autocomplete: "email", + id: "invitee_email" %> +

<%= submit_tag "Go" %>

<% end %> <% if @user %> -

<%h= 'Invitations for' %> <%= link_to @user.login, user_invitations_path(@user) %>

-<%= render :partial => 'invitations/user_invitations', :locals => {:invitations => @invitations} %> +

<%= t(".invitations_for") %> <%= link_to @user.login, user_invitations_path(@user) %>

+<%= render partial: "invitations/user_invitations", locals: { invitations: @invitations } %> <% elsif @invitation %> -<%= render :partial => 'invitations/invitation', :locals => {:invitation => @invitation} %> +<%= render partial: "invitations/invitation", locals: { invitation: @invitation } %> <% elsif @invitations %> -<%= render :partial => 'invitations/user_invitations', :locals => {:invitations => @invitations} %> +<%= render partial: "invitations/user_invitations", locals: { invitations: @invitations } %> <% end %> diff --git a/app/views/admin/admin_invitations/index.html.erb b/app/views/admin/admin_invitations/index.html.erb index 7800a0a3230..22dc1e25542 100644 --- a/app/views/admin/admin_invitations/index.html.erb +++ b/app/views/admin/admin_invitations/index.html.erb @@ -10,52 +10,69 @@ -<%= form_tag url_for(:controller => 'admin/admin_invitations', :action => :create) do |f| %> +<%= form_tag url_for(controller: "admin/admin_invitations", action: :create) do |f| %>
-

Send to email

-

Send an invite code to the following email address: - <%= text_field_tag "invitation[invitee_email]", (@invitation.try(:invitee_email) || ""), :title => ts("invite by email") %> - <%= submit_tag ts('Invite user') %> +

<%= t(".send_to_email.heading") %>

+

+ <%= t(".send_to_email.description") %> + <%= text_field_tag "invitation[invitee_email]", + (@invitation.try(:invitee_email) || ""), + autocomplete: "email", + title: t(".send_to_email.invite_by_email") %> + <%= submit_tag t(".send_to_email.invite_user") %>

<% end %> -<%= form_tag url_for(:controller => 'admin/admin_invitations', :action => 'invite_from_queue') do %> +<%= form_tag url_for(controller: "admin/admin_invitations", action: :invite_from_queue) do %>
-

Send invite codes to people in our <%= link_to 'invitations queue', invite_requests_path %>

-

There are <%= InviteRequest.count %> requests in the queue.

+

+ <%= t(".invite_from_queue.heading_html", + invitations_queue_link: link_to(t(".invite_from_queue.invitations_queue"), invite_requests_path)) %> +

+

<%= t(".invite_from_queue.requests_in_queue", count: InviteRequest.count) %>

- <%= label_tag "invitation[invite_from_queue]", ts('Number of people to invite') %>: <%= text_field_tag "invitation[invite_from_queue]" %> - <%= submit_tag ts('Invite from queue') %> + <%= label_tag "invitation[invite_from_queue]", t(".invite_from_queue.number_to_invite") %> + <%= text_field_tag "invitation[invite_from_queue]", nil, autocomplete: "on" %> + <%= submit_tag t(".invite_from_queue.invite_from_queue") %>

<% end %> -<%= form_tag url_for(:controller => 'admin/admin_invitations', :action => 'grant_invites_to_users') do %> +<%= form_tag url_for(controller: "admin/admin_invitations", action: :grant_invites_to_users) do %>
-

<%=h 'Give invite codes to current users' %>

+

<%= t(".grant_invites.heading") %>

-
<%= label_tag "invitation[number_of_invites]", ts('Number of invitations') %>:
-
<%= text_field_tag "invitation[number_of_invites]" %>
-
<%= label_tag "invitation[user_group]", ts('Users') %>:
-
<%= select_tag "invitation[user_group]", "".html_safe %>
-
Submit
-
<%= submit_tag "Generate invitations" %>
+
<%= label_tag "invitation[number_of_invites]", t(".grant_invites.number_of_invitations") %>
+
<%= text_field_tag "invitation[number_of_invites]", nil, autocomplete: "on" %>
+
<%= label_tag "invitation[user_group]", t(".grant_invites.users") %>
+
+ <%= select_tag "invitation[user_group]", + options_for_select([t(".grant_invites.all"), t(".grant_invites.with_no_unused")], + t(".grant_invites.all")) %> +
+
<%= t(".grant_invites.landmark_submit") %>
+
<%= submit_tag t(".grant_invites.generate_invitations") %>
<% end %> -<%= form_tag url_for(:controller => 'admin/admin_invitations', :action => 'find'), :method => :get do %> +<%= form_tag url_for(controller: "admin/admin_invitations", action: :find), method: :get do %>
-

<%=h 'Track invitations' %>

+

<%= t(".find.heading") %>

-
<%= label_tag "invitation[user_name]", ts('Enter a user name') %>:
-
<%= text_field_tag "invitation[user_name]" %>
-
<%= label_tag "invitation[token]", ts('Enter an invite token') %>:
-
<%= text_field_tag "invitation[token]" %>
-
<%= label_tag "track_invitation_invitee_email", t(".email") %>:
-
<%= text_field_tag "invitation[invitee_email]", nil, id: "track_invitation_invitee_email" %>
-
Submit
-
<%= submit_tag "Go" %>
+
<%= label_tag "invitation[user_name]", t(".find.enter_username") %>
+
<%= text_field_tag "invitation[user_name]", nil, autocomplete: "on" %>
+
<%= label_tag "invitation[token]", t(".find.enter_invite_token") %>
+
<%= text_field_tag "invitation[token]", nil, autocomplete: "on" %>
+
<%= label_tag "track_invitation_invitee_email", t(".find.email") %>:
+
+ <%= text_field_tag "invitation[invitee_email]", + nil, + autocomplete: "email", + id: "track_invitation_invitee_email" %> +
+
<%= t(".find.landmark_submit") %>
+
<%= submit_tag t(".find.go") %>
<% end %> diff --git a/app/views/admin/admin_users/show.html.erb b/app/views/admin/admin_users/show.html.erb index 6ca6c957f47..6e6f369cbb7 100644 --- a/app/views/admin/admin_users/show.html.erb +++ b/app/views/admin/admin_users/show.html.erb @@ -15,6 +15,9 @@
  • <%= button_to t(".navigation.activate"), { action: "activate", id: @user }, disabled: @user.active? %>
  • +
  • + <%= link_to t(".navigation.rename"), change_username_user_path(@user) %> +
  • <%= link_to t(".navigation.roles"), { action: "index", user_id: @user.id } %>
  • diff --git a/app/views/admin_sessions/new.html.erb b/app/views/admin_sessions/new.html.erb index 5d2b26b99aa..c41f120f1e2 100644 --- a/app/views/admin_sessions/new.html.erb +++ b/app/views/admin_sessions/new.html.erb @@ -1,16 +1,15 @@ -

    <%= ts("Log in as Admin") %>

    +

    <%= t(".page_heading") %>

    <%= form_for @admin_session do |form| %> -
    -
    <%= form.label :login, ts("Admin user name") %>
    -
    <%= form.text_field :login %>
    -
    <%= form.label :password, ts("Admin password") %>
    -
    <%= form.password_field :password %>
    -
    -

    <%= form.submit ts('Log in as admin') %>

    +
    +
    <%= form.label :login, t(".admin_username") %>
    +
    <%= form.text_field :login %>
    +
    <%= form.label :password, t(".admin_password") %>
    +
    <%= form.password_field :password %>
    +
    +

    <%= form.submit t(".log_in_as_admin") %>

    <% end %> - diff --git a/app/views/challenge/gift_exchange/_challenge_signups.html.erb b/app/views/challenge/gift_exchange/_challenge_signups.html.erb index c610c765b4e..091e1946863 100755 --- a/app/views/challenge/gift_exchange/_challenge_signups.html.erb +++ b/app/views/challenge/gift_exchange/_challenge_signups.html.erb @@ -1,9 +1,9 @@

    <% if @query %> - <%= search_header @challenge_signups, nil, "Sign-up" %> + <%= search_header @challenge_signups, nil, t(".heading.for_search") %> <% else %> - <%= ts("Sign-ups for %{collection}", collection: @collection.title) %> + <%= t(".heading.for_collection", collection: @collection.title) %> <% end %>

    @@ -13,13 +13,13 @@
  • - <%= link_to ts("Download (CSV)"), collection_signups_path(@collection, format: :csv) %> + <%= link_to t(".navigation.download_csv"), collection_signups_path(@collection, format: :csv) %> <%= link_to_help "csv-download" %>
  • @@ -27,13 +27,13 @@ <% if @challenge_signups.empty? %> -

    <%= ts("No sign-ups yet!")%>

    +

    <%= t(".no_sign_ups_yet") %>

    <% else %> <%= will_paginate(@challenge_signups) %>
    <% @challenge_signups.each do |signup| %> -
    "> +
    "> <%= link_to signup.pseud.name, collection_signup_path(@collection, signup) %> <%= mailto_link signup.pseud.user, subject: "[#{h(@collection.title)}] Message from Collection Maintainer" %>
    @@ -41,12 +41,12 @@ <%= render "challenge_signups/signup_controls", challenge_signup: signup, subnav: false %>
    "> @@ -62,4 +62,3 @@ <%= will_paginate(@challenge_signups) %> <% end %> - diff --git a/app/views/invitations/_user_invitations.html.erb b/app/views/invitations/_user_invitations.html.erb index 77ff5dd4c96..7cff4656337 100644 --- a/app/views/invitations/_user_invitations.html.erb +++ b/app/views/invitations/_user_invitations.html.erb @@ -1,32 +1,35 @@ <% unless invitations.blank? %> - - - - - - - - - +
    <%= ts('Invitation Information') %>
    <%= ts('Token') %><%= ts('Sent To') %><%= ts('User Name') %><%= ts('External Author') %><%= ts('Copy Link') %>
    "> + + + + + + + + - - + + <% for invitation in invitations %> - - + + <% if logged_in_as_admin? && invitation.redeemed_at.blank? %> - + <% end %> <% end %> diff --git a/app/views/preferences/index.html.erb b/app/views/preferences/index.html.erb index 86af88243b2..83855fe1090 100644 --- a/app/views/preferences/index.html.erb +++ b/app/views/preferences/index.html.erb @@ -1,160 +1,160 @@ -

    <%= ts('Set My Preferences') %>

    +

    <%= t(".page_heading") %>

    <%= error_messages_for :preference %> -

    Navigation

    +

    <%= t(".navigation.landmark") %>

    <%= form_for(@preference, url: user_preference_path(@user, @preference)) do |f| %>
    - <%= ts('Privacy') %> -

    <%= ts('Privacy') %> <%= link_to_help 'privacy-preferences' %>

    + <%= t(".privacy.legend") %> +

    <%= t(".privacy.heading") %> <%= link_to_help "privacy-preferences" %>

    • <%= f.check_box :email_visible %> - <%= f.label :email_visible, ts('Show my email address to other people.') %> + <%= f.label :email_visible, t(".privacy.show_email_address") %>
    • <%= f.check_box :date_of_birth_visible %> - <%= f.label :date_of_birth_visible, ts('Show my date of birth to other people.') %> + <%= f.label :date_of_birth_visible, t(".privacy.show_date_of_birth") %>
    • <%= f.check_box :minimize_search_engines %> - <%= f.label :minimize_search_engines, ts('Hide my work from search engines when possible.') %> + <%= f.label :minimize_search_engines, t(".privacy.hide_work_from_search_engines") %>
    • <%= f.check_box :disable_share_links %> - <%= f.label :disable_share_links, ts('Hide the share buttons on my work.') %> + <%= f.label :disable_share_links, t(".privacy.hide_share_buttons") %>
    • <%= f.check_box :allow_cocreator %> - <%= f.label :allow_cocreator, ts("Allow others to invite me to be a co-creator.") %> + <%= f.label :allow_cocreator, t(".privacy.allow_co_creator_invite") %>
    - <%= ts('Display') %> -

    <%= ts('Display') %> <%= link_to_help 'display-preferences' %>

    + <%= t(".display.legend") %> +

    <%= t(".display.heading") %> <%= link_to_help "display-preferences" %>

    • <%= f.check_box :adult %> - <%= f.label :adult, ts('Show me adult content without checking.') %> + <%= f.label :adult, t(".display.show_adult_content") %>
    • <%= f.check_box :view_full_works %> - <%= f.label :view_full_works, ts('Show the whole work by default.') %> + <%= f.label :view_full_works, t(".display.show_whole_work_default") %>
    • <%= f.check_box :hide_warnings %> - <%= f.label :hide_warnings, ts('Hide warnings (you can still choose to show them).') %> + <%= f.label :hide_warnings, t(".display.hide_warnings") %>
    • <%= f.check_box :hide_freeform %> - <%= f.label :hide_freeform, ts('Hide additional tags (you can still choose to show them).') %> + <%= f.label :hide_freeform, t(".display.hide_additional_tags") %>
    • <%= f.check_box :disable_work_skins %> - <%= f.label :disable_work_skins, ts('Hide work skins (you can still choose to show them).') %> <%= link_to_help 'skins-basics' %> + <%= f.label :disable_work_skins, t(".display.hide_work_skins") %> <%= link_to_help "skins-basics" %>
    -
    <%= f.label :skin_id, ts('Your site skin') %> <%= link_to_help 'skins-basics' %>
    +
    <%= f.label :skin_id, t(".your_site_skin") %> <%= link_to_help "skins-basics" %>
    - <%= link_to ts('Public Site Skins'), skins_path %> - <%= f.select :skin_id, @available_skins.collect{|s| [s.title, s.id]} %> + <%= link_to t(".public_site_skins"), skins_path %> + <%= f.select :skin_id, (@available_skins.collect { |s| [s.title, s.id] }) %>
    -
    <%= f.label :time_zone, ts('Your time zone') %>
    -
    <%= f.time_zone_select :time_zone, nil, :default => Time.zone.name %>
    +
    <%= f.label :time_zone, t(".your_time_zone") %>
    +
    <%= f.time_zone_select :time_zone, nil, default: Time.zone.name %>
    <% if $rollout.active?(:set_locale_preference, @user) %> -
    <%= f.label :preferred_locale, ts('Your locale') %> <%= link_to_help 'locale-preferences' %>
    +
    <%= f.label :preferred_locale, t(".your_locale") %> <%= link_to_help "locale-preferences" %>
    <%= f.select :preferred_locale, locale_options_for_select(@available_locales, "id"), default: @preference.preferred_locale %>
    <% end %> -
    <%= f.label :work_title_format, ts('Browser page title format') %> <%= link_to_help 'work_title_format' %>
    +
    <%= f.label :work_title_format, t(".browser_page_title_format") %> <%= link_to_help "work_title_format" %>
    <%= f.text_field :work_title_format %>
    - <%= ts('Comments') %> -

    <%= ts('Comments') %> <%= link_to_help 'comment-preferences' %>

    + <%= t(".comments.legend") %> +

    <%= t(".comments.heading") %> <%= link_to_help "comment-preferences" %>

    • <%= f.check_box :comment_emails_off %> - <%= f.label :comment_emails_off, ts('Turn off emails about comments.') %> + <%= f.label :comment_emails_off, t(".comments.turn_off_emails") %>
    • <%= f.check_box :comment_inbox_off %> - <%= f.label :comment_inbox_off, ts('Turn off messages to your inbox about comments.') %> + <%= f.label :comment_inbox_off, t(".comments.turn_off_inbox") %>
    • <%= f.check_box :comment_copy_to_self_off %> - <%= f.label :comment_copy_to_self_off, ts('Turn off copies of your own comments.') %> + <%= f.label :comment_copy_to_self_off, t(".comments.turn_off_copies_own_comments") %>
    • <%= f.check_box :kudos_emails_off %> - <%= f.label :kudos_emails_off, ts('Turn off emails about kudos.') %> + <%= f.label :kudos_emails_off, t(".comments.turn_off_kudos_emails") %>
    • <%= f.check_box :guest_replies_off %> - <%= f.label :guest_replies_off, t(".guest_replies_off") %> + <%= f.label :guest_replies_off, t(".comments.guest_replies_off") %>
    - <%= ts('Collections, Challenges and Gifts') %> -

    <%= ts('Collections, Challenges and Gifts') %> <%= link_to_help 'collection-preferences' %>

    + <%= t(".collections_challenges_gifts.legend") %> +

    <%= t(".collections_challenges_gifts.heading") %> <%= link_to_help "collection-preferences" %>

    • <%= f.check_box :allow_collection_invitation %> - <%= f.label :allow_collection_invitation, t(".allow_collection_invitation") %> + <%= f.label :allow_collection_invitation, t(".collections_challenges_gifts.allow_collection_invitation") %>
    • <%= f.check_box :allow_gifts %> - <%= f.label :allow_gifts, ts("Allow anyone to gift me works.") %> + <%= f.label :allow_gifts, t(".collections_challenges_gifts.allow_gifts") %>
    • <%= f.check_box :collection_emails_off %> - <%= f.label :collection_emails_off, ts('Turn off emails from collections.') %> + <%= f.label :collection_emails_off, t(".collections_challenges_gifts.turn_off_collection_emails") %>
    • <%= f.check_box :collection_inbox_off %> - <%= f.label :collection_inbox_off, ts('Turn off inbox messages from collections.') %> + <%= f.label :collection_inbox_off, t(".collections_challenges_gifts.turn_off_collection_inbox") %>
    • <%= f.check_box :recipient_emails_off %> - <%= f.label :recipient_emails_off, ts('Turn off emails about gift works.') %> + <%= f.label :recipient_emails_off, t(".collections_challenges_gifts.turn_off_gift_emails") %>
    - <%= ts('Misc') %> -

    <%= ts('Misc') %> <%= link_to_help 'misc-preferences' %>

    + <%= t(".misc.legend") %> +

    <%= t(".misc.heading") %> <%= link_to_help "misc-preferences" %>

    • <%= f.check_box :history_enabled %> - <%= f.label :history_enabled, ts('Turn on History.') %> + <%= f.label :history_enabled, t(".misc.turn_on_history") %>
    • <%= f.check_box :first_login %> - <%= f.label :first_login, ts('Turn the new user help banner back on.') %> + <%= f.label :first_login, t(".misc.turn_on_new_user_help") %>
    • <%= f.check_box :banner_seen %> - <%= f.label :banner_seen, ts('Turn off the banner showing on every page.') %> + <%= f.label :banner_seen, t(".misc.turn_off_banner_every_page") %>
    diff --git a/app/views/pseuds/_pseuds_form.html.erb b/app/views/pseuds/_pseuds_form.html.erb index 8da60f58e12..0c83662e164 100644 --- a/app/views/pseuds/_pseuds_form.html.erb +++ b/app/views/pseuds/_pseuds_form.html.erb @@ -4,23 +4,23 @@
    <% if @pseud&.name == @user.login %>

    <%= @pseud.name %>

    -

    <%= t(".change_matching_pseud_html", change_username_link: link_to(t(".change_username"), change_username_user_path(@user))) %>

    +

    <%= t(".cannot_change_matching_pseud_html", change_username_link: link_to(t(".change_username"), change_username_user_path(@user))) %>

    <% else %> <%= f.text_field :name, class: "observe_textlength", disabled: logged_in_as_admin? %> <%= generate_countdown_html("pseud_name", Pseud::NAME_LENGTH_MAX) %> <% end %>
    - +
    <%= f.label :is_default, t(".make_default") %>
    <%= f.check_box :is_default, disabled: ((@pseud.name && @user.login == @pseud.name && @pseud.is_default?) || logged_in_as_admin?) %>
    - +
    <%= f.label :description, t(".description") %>

    <%= allowed_html_instructions %>

    <%= f.text_area :description, class: "observe_textlength" %> <%= generate_countdown_html("pseud_description", Pseud::DESCRIPTION_MAX) %>
    - +
    <%= t(".icon") %>
      @@ -51,7 +51,7 @@
      <%= f.label :icon_comment_text, t(".icon_comment") %> - <%= link_to_help('pseud-icon-comment') %> + <%= link_to_help("pseud-icon-comment") %>
      <%= f.text_field :icon_comment_text, class: "observe_textlength", disabled: logged_in_as_admin? %> diff --git a/app/views/users/_admin_change_username.html.erb b/app/views/users/_admin_change_username.html.erb new file mode 100644 index 00000000000..522d7d12962 --- /dev/null +++ b/app/views/users/_admin_change_username.html.erb @@ -0,0 +1,27 @@ +

      <%= t(".page_heading") %>

      +<%= error_messages_for :user %> +

      <%= t(".description") %>

      + + + +<%= form_tag changed_username_user_path(@user) do %> +
      +
      <%= t("users.change_username.current_username") %>
      +

      <%= @user.login %>

      +
      <%= label_tag :new_login, t("users.change_username.new_username") %>
      +
      + <%= text_field_tag :new_login, "user#{@user.id}", readonly: true, autocomplete: "off", "aria-describedby": "new-login-field-description" %> +

      + <%= t(".new_username_footnote") %> +

      +
      +
      <%= label_tag :ticket_number, t(".ticket_id") %>
      +
      <%= text_field_tag :ticket_number, nil, autocomplete: "off" %>
      +
      <%= t("users.change_username.submit_landmark") %>
      +
      + <%= submit_tag t("users.change_username.change_username") %> +
      +
      +<% end %> diff --git a/app/views/users/_edit_header_navigation.html.erb b/app/views/users/_edit_header_navigation.html.erb index 0ca4fe57ad9..643714f4456 100644 --- a/app/views/users/_edit_header_navigation.html.erb +++ b/app/views/users/_edit_header_navigation.html.erb @@ -1,7 +1,7 @@ - \ No newline at end of file + diff --git a/app/views/users/_edit_user_navigation.html.erb b/app/views/users/_edit_user_navigation.html.erb index c1862e88c99..77e872ca9db 100644 --- a/app/views/users/_edit_user_navigation.html.erb +++ b/app/views/users/_edit_user_navigation.html.erb @@ -1,7 +1,7 @@ - \ No newline at end of file + diff --git a/app/views/users/change_username.html.erb b/app/views/users/change_username.html.erb index 694613a6842..e80ae23c67a 100644 --- a/app/views/users/change_username.html.erb +++ b/app/views/users/change_username.html.erb @@ -1,50 +1,53 @@ - -

      <%= ts("Change My User Name") %>

      -<%= error_messages_for :user %> -
      -

      - <%= t(".caution") %> - <%= t(".change_window", count: ArchiveConfig.USER_RENAME_LIMIT_DAYS) %> - <% if @user.renamed_at %> - <%= t(".last_renamed", renamed_at: l(@user.renamed_at, format: :long)) %> - <% end %> +<% if policy(@user).change_username? %> + <%= render "admin_change_username" %> +<% else %> + +

      <%= t(".page_heading") %>

      + <%= error_messages_for :user %> +
      +

      + <%= t(".caution") %> + <%= t(".change_window", count: ArchiveConfig.USER_RENAME_LIMIT_DAYS) %> + <% if @user.renamed_at %> + <%= t(".last_renamed", renamed_at: l(@user.renamed_at, format: :long)) %> + <% end %> +

      +

      + <%= t(".more_info_html", + account_faq_link: link_to(t(".account_faq"), archive_faq_path("your-account", anchor: "namechange")), + contact_support_link: link_to(t(".contact_support"), new_feedback_report_path)) %> +

      +
      +

      + <%= t(".new_pseud_instead_html", create_a_new_pseud_link: link_to(t(".create_a_new_pseud"), new_user_pseud_path(@user))) %>

      -

      - <%= t(".more_info", - account_faq_link: (link_to t(".account_faq"), archive_faq_path("your-account", anchor: "namechange")), - contact_support_link: (link_to t(".contact_support"), new_feedback_report_path) - ).html_safe %> -

      -
      -

      - <%= ts("If that is not what you want, you can create a new Pseud instead.").html_safe %> -

      - + - -<%= render "edit_header_navigation" %> - + + <%= render "edit_header_navigation" %> + - + -<%= form_tag changed_username_user_path(@user) do %> -
      -
      <%= ts("Current user name") %>
      -

      <%= @user.login %>

      -
      <%= label_tag :new_login, ts("New user name") %>
      -
      - <%= text_field_tag :new_login, @new_login, autocomplete: "off", "aria-describedby" => "new-login-field-description" %> -

      - <%= ts("%{minimum} to %{maximum} characters (A-Z, a-z, _, 0-9 only), no spaces, cannot begin or end with underscore (_)", - minimum: ArchiveConfig.LOGIN_LENGTH_MIN, - maximum: ArchiveConfig.LOGIN_LENGTH_MAX) %> -

      -
      -
      <%= label_tag :password, ts("Password") %>
      -
      <%= password_field_tag :password %>
      -
      <%= ts("Submit") %>
      -
      - <%= submit_tag ts("Change User Name"), data: { confirm: ts("Are you sure you want to change your user name?") } %> -
      -
      + <%= form_tag changed_username_user_path(@user) do %> +
      +
      <%= t(".current_username") %>
      +

      <%= @user.login %>

      +
      <%= label_tag :new_login, t(".new_username") %>
      +
      + <%= text_field_tag :new_login, @new_login, autocomplete: "off", "aria-describedby": "new-login-field-description" %> +

      + <%= t(".username_requirements", + minimum: ArchiveConfig.LOGIN_LENGTH_MIN, + maximum: ArchiveConfig.LOGIN_LENGTH_MAX) %> +

      +
      +
      <%= label_tag :password, t(".password") %>
      +
      <%= password_field_tag :password, nil, autocomplete: "disabled" %>
      +
      <%= t(".submit_landmark") %>
      +
      + <%= submit_tag t(".change_username"), data: { confirm: t(".confirm") } %> +
      +
      + <% end %> <% end %> diff --git a/app/views/users/passwords/new.html.erb b/app/views/users/passwords/new.html.erb index 9b61e842a00..15fa21c0ba0 100644 --- a/app/views/users/passwords/new.html.erb +++ b/app/views/users/passwords/new.html.erb @@ -1,18 +1,15 @@ -

      <%= ts("Forgotten your password?") %>

      -

      - <%= ts("If you've forgotten your password, we can send instructions that will allow you to reset it.") %> - <%= ts("Please tell us the user name or email address you used when you signed up for your Archive account.") %> -

      +

      <%= t(".page_heading") %>

      +

      <%= t(".instructions") %>

      <%= form_for resource, url: user_password_path, html: { method: :post, html: "reset password simple post" } do |f| %> <%= error_messages_for resource %>

      - <%= label_tag :reset_login, ts("Email address or user name".html_safe) %> + <%= label_tag :reset_login, t(".email_or_username_html", or: tag.strong(t(".or"))) %> <%= f.text_field :login, id: :reset_login %> - <%= f.submit ts("Reset Password") %> + <%= f.submit t(".reset_password") %>

      <% end %> diff --git a/app/views/users/registrations/_passwd.html.erb b/app/views/users/registrations/_passwd.html.erb index cd9673b00cf..68f5a38c65d 100644 --- a/app/views/users/registrations/_passwd.html.erb +++ b/app/views/users/registrations/_passwd.html.erb @@ -1,46 +1,44 @@
      - <%= f.label :login, ts("User name") %> + <%= f.label :login, t(".username") %>
      <%= f.text_field :login, "aria-describedby" => "login-field-description" %> - <%= live_validation_for_field('user_registration_login', - maximum_length: ArchiveConfig.LOGIN_LENGTH_MAX, - minimum_length: ArchiveConfig.LOGIN_LENGTH_MIN, - failureMessage: ts("You need a user name! (At least %{minimum} letters long, please.)", - minimum: ArchiveConfig.LOGIN_LENGTH_MIN)) %> + <%= live_validation_for_field("user_registration_login", + maximum_length: ArchiveConfig.LOGIN_LENGTH_MAX, + minimum_length: ArchiveConfig.LOGIN_LENGTH_MIN, + failureMessage: t(".username_validation", minimum: ArchiveConfig.LOGIN_LENGTH_MIN)) %>

      - <%= ts("%{minimum} to %{maximum} characters (A-Z, a-z, _, 0-9 only), no spaces, cannot begin or end with underscore (_)", + <%= t(".username_requirements", minimum: ArchiveConfig.LOGIN_LENGTH_MIN, maximum: ArchiveConfig.LOGIN_LENGTH_MAX) %>

      - <%= f.label :password, ts("Password") %> + <%= f.label :password, t(".password") %>
      <%= f.password_field :password, "aria-describedby" => "password-field-description" %> - <%= live_validation_for_field('user_registration_password', + <%= live_validation_for_field("user_registration_password", minimum_length: ArchiveConfig.PASSWORD_LENGTH_MIN, maximum_length: ArchiveConfig.PASSWORD_LENGTH_MAX, - failureMessage: ts("Please enter a password! (At least %{minimum} letters long, please.)", - minimum: ArchiveConfig.PASSWORD_LENGTH_MIN)) %> + failureMessage: t(".password_validation", minimum: ArchiveConfig.PASSWORD_LENGTH_MIN)) %>

      - <%= ts("%{minimum} to %{maximum} characters", - minimum: ArchiveConfig.PASSWORD_LENGTH_MIN, - maximum: ArchiveConfig.PASSWORD_LENGTH_MAX) %> + <%= t(".password_requirements", + minimum: ArchiveConfig.PASSWORD_LENGTH_MIN, + maximum: ArchiveConfig.PASSWORD_LENGTH_MAX) %>

      -
      <%= f.label :password_confirmation, ts("Confirm password") %>
      +
      <%= f.label :password_confirmation, t(".confirm_password") %>
      <%= f.password_field :password_confirmation %> - <%= live_validation_for_field('user_registration_password_confirmation', + <%= live_validation_for_field("user_registration_password_confirmation", minimum_length: ArchiveConfig.PASSWORD_LENGTH_MIN, maximum_length: ArchiveConfig.PASSWORD_LENGTH_MAX, - failureMessage: ts("Please enter the same password in both fields.")) %> + failureMessage: t(".confirm_password_validation")) %>
      - <%= f.label :email, ts("Valid email") %> + <%= f.label :email, t(".valid_email") %>
      <%= f.text_field :email %>
      diff --git a/app/views/users/sessions/_passwd.html.erb b/app/views/users/sessions/_passwd.html.erb index f025b7f83c7..db6eeb18a5b 100644 --- a/app/views/users/sessions/_passwd.html.erb +++ b/app/views/users/sessions/_passwd.html.erb @@ -1,14 +1,14 @@ <%= form_for(User.new, url: new_user_session_path) do |f| %>
      -
      <%= f.label :login, ts("User name or email:") %>
      +
      <%= f.label :login, t(".username_or_email") %>
      <%= f.text_field :login %>
      -
      <%= f.label :password, ts("Password:") %>
      +
      <%= f.label :password, t(".password") %>
      <%= f.password_field :password %>
      -
      <%= f.label :remember_me, ts("Remember me") %>
      +
      <%= f.label :remember_me, t(".remember_me") %>
      <%= f.check_box :remember_me %>
      -
      <%= ts("Submit") %>
      +
      <%= t(".landmark_submit") %>
      - <%= f.submit ts("Log in"), class: "submit" %> + <%= f.submit t(".log_in"), class: "submit" %>
      <% end %> diff --git a/app/views/users/sessions/_passwd_small.html.erb b/app/views/users/sessions/_passwd_small.html.erb index 1d49f0b7704..3ebcdeb0a22 100644 --- a/app/views/users/sessions/_passwd_small.html.erb +++ b/app/views/users/sessions/_passwd_small.html.erb @@ -1,32 +1,29 @@ -<% # We need to override the ids to avoid accessibility issues on the new user - # session page, which has a second user session form %> +<%# We need to override the ids to avoid accessibility issues on the new user session page, +which has a second user session form %> <%= form_for(User.new, url: user_session_path, html: { id: "new_user_session_small" }) do |f| %> -
      -
      - <%= f.label :login, ts("User name or email:"), - for: "user_session_login_small" %>
      -
      <%= f.text_field :login, - id: "user_session_login_small" %>
      -
      <%= f.label :password, ts("Password:"), - for: "user_session_password_small" %>
      -
      <%= f.password_field :password, - id: "user_session_password_small" %>
      +
      +
      <%= f.label :login, t(".username_or_email"), for: "user_session_login_small" %>
      +
      <%= f.text_field :login, autocomplete: "on", id: "user_session_login_small" %>
      +
      <%= f.label :password, t(".password"), for: "user_session_password_small" %>
      +
      <%= f.password_field :password, id: "user_session_password_small" %>

      - - <%= f.submit ts("Log In") %> + + <%= f.submit t(".log_in") %>

      <% end %>
        -
      • <%= link_to ts("Forgot password?"), new_user_password_path %>
      • +
      • <%= link_to t(".forgot_password"), new_user_password_path %>
      • <% if AdminSetting.current.account_creation_enabled? && !AdminSetting.current.creation_requires_invite? %>
      • - <%= link_to ts("Create an Account"), signup_path %> + <%= link_to t(".create_an_account"), signup_path %>
      • <% elsif AdminSetting.current.invite_from_queue_enabled? %>
      • - <%= link_to ts("Get an Invitation"), invite_requests_path %> + <%= link_to t(".get_an_invitation"), invite_requests_path %>
      • <% end %>
      diff --git a/config/initializers/rack_attack.rb b/config/initializers/rack_attack.rb index 248d13f10d2..4eaf44002d5 100644 --- a/config/initializers/rack_attack.rb +++ b/config/initializers/rack_attack.rb @@ -69,7 +69,7 @@ class Rack::Attack req.ip if req.path == "/users/login" && req.post? end - # Throttle POST requests to /users/login by login param (user name or email) + # Throttle POST requests to /users/login by login param (username or email) # # Key: "rack::attack:#{Time.now.to_i/:period}:logins/email:#{login}" # diff --git a/config/locales/controllers/en.yml b/config/locales/controllers/en.yml index b310e500791..a7ec7a58fda 100644 --- a/config/locales/controllers/en.yml +++ b/config/locales/controllers/en.yml @@ -116,6 +116,19 @@ en: muted: You have muted the user %{name}. destroy: unmuted: You have unmuted the user %{name}. + pseuds: + create: + already_have_pseud_with_name: You already have a pseud with that name. + successfully_created: Pseud was successfully created. + destroy: + cannot_delete_default: You cannot delete your default pseudonym, sorry! + cannot_delete_matching_username: You cannot delete the pseud matching your username, sorry! + not_deleted: The pseud was not deleted. + successfully_deleted: The pseud was successfully deleted. + show: + could_not_find_user: Couldn't find user '%{username}' + update: + successfully_updated: Pseud was successfully updated. questions: not_found: Sorry, we couldn't find the FAQ you were looking for. update_positions: @@ -124,6 +137,12 @@ en: index: page_subtitle: fandoms users: + changed_username: + admin: + successfully_updated: Username has been successfully updated. + user: + incorrect_password: Your password was incorrect + successfully_updated: Your username has been successfully updated. contact_abuse: contact Policy & Abuse passwords: create: diff --git a/config/locales/devise/en.yml b/config/locales/devise/en.yml index e6839d9f580..fc4ca045161 100644 --- a/config/locales/devise/en.yml +++ b/config/locales/devise/en.yml @@ -9,20 +9,20 @@ en: admin: already_authenticated: You are already signed in. inactive: Your account is not activated yet. - invalid: The password or admin user name you entered doesn't match our records. + invalid: The password or admin username you entered doesn't match our records. last_attempt: You have one more attempt before your account is locked. locked: Your account is locked. - not_found_in_database: The password or admin user name you entered doesn't match our records. + not_found_in_database: The password or admin username you entered doesn't match our records. timeout: Your session expired. Please sign in again to continue. unauthenticated: You need to sign in or sign up before continuing. unconfirmed: You have to confirm your email address before continuing. user: already_authenticated: You are already signed in. inactive: You'll need to activate your account before you can log in. Please check your email or contact support. - invalid: The password or user name you entered doesn't match our records. Please try again or reset your password. If you still can't log in, please visit Problems When Logging In for help. + invalid: The password or username you entered doesn't match our records. Please try again or reset your password. If you still can't log in, please visit Problems When Logging In for help. last_attempt: You have one more attempt before your account is locked. locked: Your account has been locked for 5 minutes due to too many failed login attempts. - not_found_in_database: The password or user name you entered doesn't match our records. Please try again or reset your password. If you still can't log in, please visit Problems When Logging In for help. + not_found_in_database: The password or username you entered doesn't match our records. Please try again or reset your password. If you still can't log in, please visit Problems When Logging In for help. timeout: Your session expired. Please sign in again to continue. unauthenticated: You need to sign in or sign up before continuing. unconfirmed: You have to activate your account before continuing. Please check your email for the activation link. diff --git a/config/locales/mailers/en.yml b/config/locales/mailers/en.yml index 16c85b34011..88f18a01871 100644 --- a/config/locales/mailers/en.yml +++ b/config/locales/mailers/en.yml @@ -135,8 +135,8 @@ en: tos_violation: If your work was hidden due to being in violation of the Archive of Our Own's Terms of Service (%{tos_url}), you will be required to take action to correct the violation. Failure to bring your work into compliance with the Terms of Service may lead to your work being deleted from the Archive. tos: Terms of Service anonymous_or_unrevealed_notification: - anonymous_info: Anonymous works are included in tag listings, but not on your works page. On the work, your user name will be replaced with "Anonymous." - anonymous_unrevealed_info: The collection maintainers may later reveal your work but leave it anonymous. People who subscribe to you will not be notified of this change. Your work will be included in tag listings, but not on your works page. On the work, your user name will be replaced with "Anonymous." + anonymous_info: Anonymous works are included in tag listings, but not on your works page. On the work, your username will be replaced with "Anonymous." + anonymous_unrevealed_info: The collection maintainers may later reveal your work but leave it anonymous. People who subscribe to you will not be notified of this change. Your work will be included in tag listings, but not on your works page. On the work, your username will be replaced with "Anonymous." changed_status: anonymous: html: The collection maintainers of %{collection_link} have changed the status of your work %{work_link} to anonymous. diff --git a/config/locales/models/en.yml b/config/locales/models/en.yml index 1c9c25b5f26..4c8fd6a81c7 100644 --- a/config/locales/models/en.yml +++ b/config/locales/models/en.yml @@ -75,7 +75,7 @@ en: skin/skin_parents: parent_skin: Parent skin user: - login: User name + login: Username work: chapter_total_display: Chapters summary: Summary @@ -180,9 +180,10 @@ en: accepted: Sorry, you need to consent to the processing of your personal data in order to sign up. format: "%{message}" login: + admin_must_use_default: must use the default. Please contact your chairs to use something else. changed_too_recently: - one: can only be changed once per day. You last changed your user name on %{renamed_at}. - other: can only be changed once every %{count} days. You last changed your user name on %{renamed_at}. + one: can only be changed once per day. You last changed your username on %{renamed_at}. + other: can only be changed once every %{count} days. You last changed your username on %{renamed_at}. invalid: must be %{min_login} to %{max_login} characters (A-Z, a-z, _, 0-9 only), no spaces, cannot begin or end with underscore (_). password_confirmation: confirmation: doesn't match new password. diff --git a/config/locales/views/en.yml b/config/locales/views/en.yml index 3d2c6a20a1f..1899c50d320 100644 --- a/config/locales/views/en.yml +++ b/config/locales/views/en.yml @@ -82,15 +82,44 @@ en: target: Target admin_invitations: find: - email: Enter all or part of an email address - token: Enter an invite token - user_name: Enter a user name + email: 'Enter all or part of an email address:' + invitations_for: Invitations for + page_heading: Track invitations + token: 'Enter an invite token:' + username: 'Enter a username:' index: - email: Enter all or part of an email address + find: + email: Enter all or part of an email address + enter_invite_token: 'Enter an invite token:' + enter_username: 'Enter a username:' + go: Go + heading: Track invitations + landmark_submit: Submit + grant_invites: + all: All + generate_invitations: Generate invitations + heading: Give invite codes to current users + landmark_submit: Submit + number_of_invitations: 'Number of invitations:' + users: 'Users:' + with_no_unused: With no unused invitations + invite_from_queue: + heading_html: Send invite codes to people in our %{invitations_queue_link} + invitations_queue: invitations queue + invite_from_queue: Invite from queue + number_to_invite: 'Number of people to invite:' + requests_in_queue: + one: There is 1 request in the queue. + other: There are %{count} requests in the queue. navigation: queue: Manage Queue requests: Manage Requests page_heading: Invite New Users + send_to_email: + description: 'Send an invite code to the following email address:' + heading: Send to Email + invite_by_email: invite by email + invite_user: Invite user admin_nav: ao3_news: AO3 News archive_faq: Archive FAQ @@ -180,6 +209,7 @@ en: invitations: add: Add Invitations manage: Manage Invitations + rename: Rename 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." @@ -307,14 +337,14 @@ en: page_heading: Set My Admin Password submit: Set Admin Password new: - instructions: If you've forgotten or would like to change your admin password, we can send instructions that will allow you to reset it. Please tell us the user name for your admin account. + instructions: If you've forgotten or would like to change your admin password, we can send instructions that will allow you to reset it. Please tell us the username for your admin account. page_heading: Forgotten your admin password? - reset_login_html: Admin user name + reset_login_html: Admin username submit: Reset Admin Password sessions: new: label: - login: Admin user name + login: Admin username password: Admin password landmark: reset: Reset password @@ -378,6 +408,12 @@ en: next: Next Post previous: Previous Post page_heading: AO3 News + admin_sessions: + new: + admin_password: Admin password + admin_username: Admin username + log_in_as_admin: Log in as admin + page_heading: Log in as Admin admins: index: confidentiality_reminder: You are now logged in as an admin. That means you will probably encounter information that is personal or confidential (e.g. usernames, email and IP addresses, creator names on anonymous works, etc). Please do not use this information in ways unrelated to your OTW role. If you have questions about what you can or cannot do with information you see here, contact your committee chair(s). @@ -462,6 +498,22 @@ en: comments_on_works: delete or hide comments they previously left on your works; you can delete these individually hide_works: hide their works or bookmarks from you intro: 'Blocking a user will not:' + challenge: + gift_exchange: + challenge_signups: + close_offers_html: Close Offers %{up_arrow} + close_requests_html: Close Requests %{up_arrow} + heading: + for_collection: Sign-ups for collection %{collection} + for_search: Sign-up + navigation: + download_csv: Download (CSV) + search: search + search_by_pseud: Search By Pseud + no_sign_ups_yet: No sign-ups yet! + offers_html: Offers %{down_arrow} + participant_username: username + requests_html: Requests %{down_arrow} challenge_signups: signup_form: notice: @@ -1359,6 +1411,17 @@ en: invitations: invitation: email_address_label: Enter an email address + user_invitations: + copy_and_use: copy and use + copy_link: Copy Link + delete: Delete + delete_confirmation: Are you sure you want to delete this invitation? + external_author: External Author + invitation_information: Invitation Information + list_of_your_invitations: List of your invitation tokens and information regarding who you shared them with, along with the option to share unused tokens. + sent_to: Sent To + token: Token + username: Username invite_requests: index_open: add_to_list: Add me to the list @@ -1543,10 +1606,58 @@ en: 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. - blocked_users: Blocked Users - guest_replies_off: Do not allow guests to reply to my comments on news posts or other users' works (you can still control the comment settings for your works separately). - muted_users: Muted Users + browser_page_title_format: Browser page title format + collections_challenges_gifts: + allow_collection_invitation: Allow others to invite my works to collections. + allow_gifts: Allow anyone to gift me works. + heading: Collections, Challenges and Gifts + legend: Collections, Challenges and Gifts + turn_off_collection_emails: Turn off emails from collections. + turn_off_collection_inbox: Turn off inbox messages from collections. + turn_off_gift_emails: Turn off emails about gift works. + comments: + guest_replies_off: Do not allow guests to reply to my comments on news posts or other users' works (you can still control the comment settings for your works separately). + heading: Comments + legend: Comments + turn_off_copies_own_comments: Turn off copies of your own comments. + turn_off_emails: Turn off emails about comments. + turn_off_inbox: Turn off messages to your inbox about comments. + turn_off_kudos_emails: Turn off emails about kudos. + display: + heading: Display + hide_additional_tags: Hide additional tags (you can still choose to show them). + hide_warnings: Hide warnings (you can still choose to show them). + hide_work_skins: Hide work skins (you can still choose to show them). + legend: Display + show_adult_content: Show me adult content without checking. + show_whole_work_default: Show the whole work by default. + misc: + heading: Misc + legend: Misc + turn_off_banner_every_page: Turn off the banner showing on every page. + turn_on_history: Turn on History. + turn_on_new_user_help: Turn the new user help banner back on. + navigation: + blocked_users: Blocked Users + change_my_username: Change My Username + edit_my_profile: Edit My Profile + landmark: Navigation + manage_my_pseuds: Manage My Pseuds + muted_users: Muted Users + orphan_my_works: Orphan My Works + page_heading: Set My Preferences + privacy: + allow_co_creator_invite: Allow others to invite me to be a co-creator. + heading: Privacy + hide_share_buttons: Hide the share buttons on my work. + hide_work_from_search_engines: Hide my work from search engines when possible. + legend: Privacy + show_date_of_birth: Show my date of birth to other people. + show_email_address: Show my email address to other people. + public_site_skins: Public Site Skins + your_locale: Your locale + your_site_skin: Your site skin + your_time_zone: Your time zone profile: pseud_list: more_pseuds: @@ -1578,8 +1689,8 @@ en: orphan_landmark_text: " by %{pseud}" user_actions: User Actions pseuds_form: - change_matching_pseud_html: You cannot change the pseud that matches your user name. However, you can %{change_username_link} instead. - change_username: change your user name + cannot_change_matching_pseud_html: You cannot change the pseud that matches your username. However, you can %{change_username_link} instead. + change_username: change your username description: Description icon: Icon icon_alt: Icon alt text @@ -1697,6 +1808,13 @@ en: description: Recalculate the filters for this work based on the current set of tags. Use this option if wrangling seems to have gone wrong. (e.g. If you synned one of this work's tags to a canonical but it's not showing up in the tag listings, or if the wrong tags are listed in the sidebar when you drill down to a search that includes only this work.) title: Update Work Filters users: + admin_change_username: + description: Change the name of this user to a generic name in the format user + their account ID. + navigation: + manage_user: Manage User + new_username_footnote: This username cannot be edited. If you need to change it to a different name, contact your chair. + page_heading: Change Username + ticket_id: Ticket ID change_email: browser_title: Change Email change_password: @@ -1705,12 +1823,22 @@ en: account_faq: Account FAQ browser_title: Change Username caution: Please use this feature with caution. + change_username: Change Username change_window: - one: You can change your user name once per day. - other: You can change your user name once every %{count} days. + one: You can change your username once per day. + other: You can change your username once every %{count} days. + confirm: Are you sure you want to change your username? contact_support: contact Support - last_renamed: You last changed your user name on %{renamed_at}. - more_info: For information on how changing your user name will affect your account, please check out the %{account_faq_link}. Note that changes to your user name may take several days or longer to appear. If you are still seeing your old user name on your works, bookmarks, series, or collections after a week, please %{contact_support_link}. + create_a_new_pseud: create a new Pseud + current_username: Current username + last_renamed: You last changed your username on %{renamed_at}. + more_info_html: For information on how changing your username will affect your account, please check out the %{account_faq_link}. Note that changes to your username may take several days or longer to appear. If you are still seeing your old username on your works, bookmarks, series, or collections after a week, please %{contact_support_link}. + new_pseud_instead_html: If that is not what you want, you can %{create_a_new_pseud_link} instead. + new_username: New username + page_heading: Change My Username + password: Password + submit_landmark: Submit + username_requirements: "%{minimum} to %{maximum} characters (A-Z, a-z, _, 0-9 only), no spaces, cannot begin or end with underscore (_)" confirmation: contact_support: contact Support go_back: Return to Archive front page @@ -1756,11 +1884,30 @@ en: public_information_notice_html: Any personal information you post on your public AO3 profile, including but not limited to your name, email, age, location, personal relationships, gender or sexual identity, racial or ethnic background, religious or political views, and/or account usernames for other sites, will be accessible by the general public. To learn more about what data AO3 collects when you're on the site and how we use it, check out our %{privacy_policy_link}. title: Title update: Update + edit_header_navigation: + change_email: Change Email + change_password: Change Password + change_username: Change Username + edit_default_pseud_and_icon: Edit Default Pseud and Icon + edit_profile: Edit Profile + edit_user_navigation: + change_email: Change Email + change_password: Change Password + change_username: Change Username + edit_default_pseud_and_icon: Edit Default Pseud and Icon + edit_my_profile: Edit My Profile header_navigation: admin_user: User Administration edit_multiple: Edit Works invitations: Invitations new_work: Post New + passwords: + new: + email_or_username_html: Email address %{or} username + instructions: If you've forgotten your password, we can send instructions that will allow you to reset it. Please tell us the username or email address you used when you signed up for your Archive account. + or: or + page_heading: Forgotten your password? + reset_password: Reset Password registrations: legal: agreement_confirm: Yes, I have read the Terms of Service, including the Content Policy and Privacy Policy, and agree to them. @@ -1779,6 +1926,16 @@ en: user: User Details submit: Create Account wait: Please wait... + passwd: + confirm_password: Confirm password + confirm_password_validation: Please enter the same password in both fields. + password: Password + password_requirements: "%{minimum} to %{maximum} characters" + password_validation: Please enter a password! (At least %{minimum} letters long, please.) + username: Username + username_requirements: "%{minimum} to %{maximum} characters (A-Z, a-z, _, 0-9 only), no spaces, cannot begin or end with underscore (_)" + username_validation: You need a username! (At least %{minimum} letters long, please.) + valid_email: Valid email sessions: greeting: nav: @@ -1808,7 +1965,7 @@ en: warning: This site is in beta. Things may break or crash without notice. login: create_account: Create an account now - forgot: Forgot your password or user name? %{reset_password_link}. + forgot: Forgot your password or username? %{reset_password_link}. log_in: Log in no_account: Don't have an account? %{join_link}. request_invite: Request an invitation to join @@ -1821,6 +1978,20 @@ en: signup: Or join us for free - it's easy. sorry: Sorry! work_unavailable: This work is only available to registered users of the Archive. + passwd: + landmark_submit: Submit + log_in: Log in + password: 'Password:' + remember_me: Remember me + username_or_email: 'Username or email:' + passwd_small: + create_an_account: Create an Account + forgot_password: Forgot password? + get_an_invitation: Get an Invitation + log_in: Log In + password: 'Password:' + remember_me: Remember Me + username_or_email: 'Username or email:' show: login_banner: contact_abuse: contact our Policy & Abuse team diff --git a/factories/users.rb b/factories/users.rb index 8d83adafefb..61da64a1b6d 100644 --- a/factories/users.rb +++ b/factories/users.rb @@ -26,7 +26,7 @@ confirmed_at { nil } end - # User names used in mailer preview should be unique but recognizable as user names + # Usernames used in mailer preview should be unique but recognizable as usernames trait :for_mailer_preview do login { "User#{Faker::Alphanumeric.alpha(number: 8)}" } end diff --git a/features/admins/admin_invitations.feature b/features/admins/admin_invitations.feature index 30e5d1de468..c28c04d6b61 100644 --- a/features/admins/admin_invitations.feature +++ b/features/admins/admin_invitations.feature @@ -306,7 +306,7 @@ Feature: Admin Actions to Manage Invitations And "dax" has "2" invitations And I am logged in as an admin When I follow "Invite New Users" - And I fill in "Enter a user name" with "dax" + And I fill in "Enter a username" with "dax" And I press "Go" Then I should see "copy and use" When I follow "Invite New Users" @@ -332,10 +332,10 @@ Feature: Admin Actions to Manage Invitations Scenario: An admin can't find a invitation for a nonexistent user Given I am logged in as an admin And I follow "Invite New Users" - When I fill in "Enter a user name" with "dax" + When I fill in "Enter a username" with "dax" And I press "Go" Then I should see "No results were found. Try another search" - When I fill in "Enter a user name" with "" + When I fill in "Enter a username" with "" And I fill in "Enter all or part of an email address" with "nonexistent@domain.com" And I press "Go" Then I should see "No results were found. Try another search" @@ -349,7 +349,7 @@ Feature: Admin Actions to Manage Invitations Then I should see "There are 2 requests in the queue." When I fill in "Number of people to invite" with "1" And press "Invite from queue" - Then I should see "There are 1 requests in the queue." + Then I should see "There is 1 request in the queue." And I should see "1 person from the invite queue is being invited" And 1 email should be delivered to "fred@bedrock.com" @@ -370,7 +370,7 @@ Feature: Admin Actions to Manage Invitations And "dax" has "2" invitations And I am logged in as a "support" admin When I follow "Invite New Users" - And I fill in "Enter a user name" with "dax" + And I fill in "Enter a username" with "dax" And I press "Go" Then I should see "copy and use" When I follow "Invite New Users" diff --git a/features/admins/authenticate_admins.feature b/features/admins/authenticate_admins.feature index d8aa3a30eee..fa961a11045 100644 --- a/features/admins/authenticate_admins.feature +++ b/features/admins/authenticate_admins.feature @@ -6,21 +6,21 @@ Feature: Authenticate Admin Users | login | password | | Zooey | adminpassword | When I go to the home page - And I fill in "User name or email" with "Zooey" + And I fill in "Username or email" with "Zooey" And I fill in "Password" with "adminpassword" And I press "Log In" - Then I should see "The password or user name you entered doesn't match our records" + Then I should see "The password or username you entered doesn't match our records" Scenario: Ordinary user cannot log in or reset password as admin. Given the following activated user exists | login | password | | dizmo | wrangulator | When I go to the admin login page - And I fill in "Admin user name" with "dizmo" + And I fill in "Admin username" with "dizmo" And I fill in "Admin password" with "wrangulator" And I press "Log In as Admin" Then I should not see "Successfully logged in" - And I should see "The password or admin user name you entered doesn't match our records." + And I should see "The password or admin username you entered doesn't match our records." When I am logged in as "dizmo" with password "wrangulator" And I go to the new admin password page Then I should be on the homepage @@ -62,17 +62,17 @@ Feature: Authenticate Admin Users | Zooey | adminpassword | And I have loaded the "roles" fixture When I go to the admin login page - And I fill in "Admin user name" with "Zooey" + And I fill in "Admin username" with "Zooey" And I fill in "Admin password" with "adminpassword" And I press "Log In as Admin" Then I should see "Successfully logged in" - Scenario: Admin user name is case insensitive. + Scenario: Admin username is case insensitive. Given the following admin exists | login | password | | TheMadAdmin | adminpassword | When I go to the admin login page - And I fill in "Admin user name" with "themadadmin" + And I fill in "Admin username" with "themadadmin" And I fill in "Admin password" with "adminpassword" And I press "Log In as Admin" Then I should see "Successfully logged in" @@ -82,10 +82,10 @@ Feature: Authenticate Admin Users | login | password | | Zooey | adminpassword | When I go to the admin login page - And I fill in "Admin user name" with "Zooey" + And I fill in "Admin username" with "Zooey" And I fill in "Admin password" with "wrongpassword" And I press "Log In" - Then I should see "The password or user name you entered doesn't match our records." + Then I should see "The password or username you entered doesn't match our records." Scenario: Admin resets password. Given the following admin exists @@ -95,7 +95,7 @@ Feature: Authenticate Admin Users When I go to the admin login page And I follow "Forgot admin password?" Then I should see "Forgotten your admin password?" - When I fill in "Admin user name" with "admin" + When I fill in "Admin username" with "admin" And I press "Reset Admin Password" Then I should see "Check your email for instructions on how to reset your password." And 1 email should be delivered to "admin@example.com" @@ -115,7 +115,7 @@ Feature: Authenticate Admin Users When I go to the admin login page And I follow "Forgot admin password?" Then I should see "Forgotten your admin password?" - When I fill in "Admin user name" with "admin" + When I fill in "Admin username" with "admin" And I press "Reset Admin Password" Then I should see "Check your email for instructions on how to reset your password." And 1 email should be delivered to "admin@example.com" @@ -130,7 +130,7 @@ Feature: Authenticate Admin Users Scenario: Locked admin cannot sign in. Given the admin "admin" is locked When I go to the admin login page - And I fill in "Admin user name" with "admin" + And I fill in "Admin username" with "admin" And I fill in "Admin password" with "adminpassword" And I press "Log In as Admin" Then I should see "Your account is locked." @@ -141,7 +141,7 @@ Feature: Authenticate Admin Users And all emails have been delivered And I am on the admin login page When I follow "Forgot admin password?" - And I fill in "Admin user name" with "admin" + And I fill in "Admin username" with "admin" And I press "Reset Admin Password" Then I should see "Check your email for instructions on how to reset your password." And 1 email should be delivered @@ -152,7 +152,7 @@ Feature: Authenticate Admin Users And I press "Set Admin Password" Then I should see "Your password has been changed successfully. Your account is locked." When the admin "admin" is unlocked - And I fill in "Admin user name" with "admin" + And I fill in "Admin username" with "admin" And I fill in "Admin password" with "newpassword" And I press "Log In as Admin" Then I should see "Successfully logged in." diff --git a/features/admins/users/admin_abuse_users.feature b/features/admins/users/admin_abuse_users.feature index a1aa93692fb..4c796f82003 100644 --- a/features/admins/users/admin_abuse_users.feature +++ b/features/admins/users/admin_abuse_users.feature @@ -227,3 +227,13 @@ Feature: Admin Abuse actions Then I should see "Are you sure you want to delete" When I press "Yes, Delete All Spammer Creations" Then I should see "All creations by user Spamster have been deleted." + + Scenario: Rename a user with an inappropriate username + Given the user "otheruserstinks" exists and is activated + And I am logged in as a "policy_and_abuse" admin + And an abuse ticket ID exists + When I visit the change username page for otheruserstinks + And I fill in "Ticket ID" with "480000" + And I press "Change Username" + Then I should see "Username has been successfully updated." + But I should not see "otheruserstinks" within "h2.heading" diff --git a/features/admins/users/admin_fnok.feature b/features/admins/users/admin_fnok.feature index 45096b1cbe5..21818165397 100644 --- a/features/admins/users/admin_fnok.feature +++ b/features/admins/users/admin_fnok.feature @@ -78,9 +78,9 @@ Feature: Admin Fannish Next Of Kind actions Given the fannish next of kin "libby" for the user "harrykim" And I am logged in as "libby" When I visit the change username page for libby - And I fill in "New user name" with "newlibby" + And I fill in "New username" with "newlibby" And I fill in "Password" with "password" - And I press "Change User Name" + And I press "Change Username" Then I should get confirmation that I changed my username When I am logged in as a "support" admin And I go to the manage users page @@ -92,9 +92,9 @@ Feature: Admin Fannish Next Of Kind actions Given the fannish next of kin "libby" for the user "harrykim" And I am logged in as "harrykim" When I visit the change username page for harrykim - And I fill in "New user name" with "harrykim2" + And I fill in "New username" with "harrykim2" And I fill in "Password" with "password" - And I press "Change User Name" + And I press "Change Username" Then I should get confirmation that I changed my username When I am logged in as a "support" admin And I go to the manage users page diff --git a/features/comments_and_kudos/kudos.feature b/features/comments_and_kudos/kudos.feature index 6361c32603f..2553278cbbe 100644 --- a/features/comments_and_kudos/kudos.feature +++ b/features/comments_and_kudos/kudos.feature @@ -208,9 +208,9 @@ Feature: Kudos And I press "Kudos ♥" Then I should see "oldusername1 left kudos on this work!" When I visit the change username page for oldusername1 - And I fill in "New user name" with "newusername1" + And I fill in "New username" with "newusername1" And I fill in "Password" with "password" - And I press "Change User Name" + And I press "Change Username" Then I should get confirmation that I changed my username And I should see "Hi, newusername1" When the kudos cache has expired diff --git a/features/other_a/profile_edit.feature b/features/other_a/profile_edit.feature index 1f9e0e6b593..18ea8853105 100644 --- a/features/other_a/profile_edit.feature +++ b/features/other_a/profile_edit.feature @@ -124,7 +124,7 @@ Scenario: Changing email address after requesting password reset When I am logged out And I follow "Forgot password?" - And I fill in "Email address or user name" with "editname" + And I fill in "Email address or username" with "editname" And I press "Reset Password" Then 1 email should be delivered to "bar@ao3.org" When all emails have been delivered diff --git a/features/other_a/pseuds.feature b/features/other_a/pseuds.feature index 077c1407e00..3f22f6c7beb 100644 --- a/features/other_a/pseuds.feature +++ b/features/other_a/pseuds.feature @@ -9,7 +9,7 @@ Scenario: pseud creation and playing with the default pseud # Check that you can't edit your default pseud. Then I should see "Default Pseud" When I follow "Edit" - Then I should see "You cannot change the pseud that matches your user name." + Then I should see "You cannot change the pseud that matches your username." And the "Make this name default" checkbox should be checked and disabled # Make a new default pseud called "Me." diff --git a/features/step_definitions/admin_steps.rb b/features/step_definitions/admin_steps.rb index fa8e38d8926..118a5231910 100644 --- a/features/step_definitions/admin_steps.rb +++ b/features/step_definitions/admin_steps.rb @@ -22,7 +22,7 @@ login = "testadmin-#{role}" FactoryBot.create(:admin, login: login, roles: [role]) if Admin.find_by(login: login).nil? visit new_admin_session_path - fill_in "Admin user name", with: login + fill_in "Admin username", with: login fill_in "Admin password", with: "adminpassword" click_button "Log In as Admin" step %{I should see "Successfully logged in"} @@ -32,7 +32,7 @@ step "I start a new session" FactoryBot.create(:admin, login: "testadmin", email: "testadmin@example.org") if Admin.find_by(login: "testadmin").nil? visit new_admin_session_path - fill_in "Admin user name", with: "testadmin" + fill_in "Admin username", with: "testadmin" fill_in "Admin password", with: "adminpassword" click_button "Log In as Admin" step %{I should see "Successfully logged in"} diff --git a/features/step_definitions/support_steps.rb b/features/step_definitions/support_steps.rb index 42e22148ddb..429e4af909d 100644 --- a/features/step_definitions/support_steps.rb +++ b/features/step_definitions/support_steps.rb @@ -13,8 +13,6 @@ end Then "a Zoho ticket should be created with referer {string}" do |referer| - # rubocop:disable Lint/AmbiguousBlockAssociation expect(WebMock).to have_requested(:post, "https://desk.zoho.com/api/v1/tickets") .with { |req| JSON.parse(req.body)["cf"]["cf_url"] == referer } - # rubocop:enable Lint/AmbiguousBlockAssociation end diff --git a/features/step_definitions/user_steps.rb b/features/step_definitions/user_steps.rb index a742a90c7ea..e422b295816 100644 --- a/features/step_definitions/user_steps.rb +++ b/features/step_definitions/user_steps.rb @@ -99,7 +99,7 @@ step %{I am on the homepage} find_link('login-dropdown').click - fill_in "User name or email:", with: login + fill_in "Username or email:", with: login fill_in "Password:", with: password check "Remember Me" click_button "Log In" @@ -136,7 +136,7 @@ page.driver.reset! end -Given "the user name {string} is on the forbidden list" do |username| +Given "the username {string} is on the forbidden list" do |username| allow(ArchiveConfig).to receive(:FORBIDDEN_USERNAMES).and_return([username]) end @@ -243,14 +243,14 @@ When "I request a password reset for {string}" do |login| step(%{I am on the login page}) step(%{I follow "Reset password"}) - step(%{I fill in "Email address or user name" with "#{login}"}) + step(%{I fill in "Email address or username" with "#{login}"}) step(%{I press "Reset Password"}) end # THEN -Then /^I should get the error message for wrong username or password$/ do - step(%{I should see "The password or user name you entered doesn't match our records. Please try again"}) +Then "I should get the error message for wrong username or password" do + step(%{I should see "The password or username you entered doesn't match our records. Please try again"}) end Then /^I should get an activation email for "(.*?)"$/ do |login| @@ -314,14 +314,14 @@ def get_series_name(age, classname, name) When /^I change my username to "([^"]*)"/ do |new_name| visit change_username_user_path(User.current_user) - fill_in("New user name", with: new_name) + fill_in("New username", with: new_name) fill_in("Password", with: "password") - click_button("Change User Name") + click_button("Change Username") step %{I should get confirmation that I changed my username} end Then /^I should get confirmation that I changed my username$/ do - step(%{I should see "Your user name has been successfully updated."}) + step(%{I should see "Your username has been successfully updated."}) end Then /^the user "([^"]*)" should be activated$/ do |login| diff --git a/features/users/authenticate_users.feature b/features/users/authenticate_users.feature index 9c3459520c6..cf9de30bea1 100644 --- a/features/users/authenticate_users.feature +++ b/features/users/authenticate_users.feature @@ -9,14 +9,14 @@ Feature: User Authentication | sam | secret | And all emails have been delivered When I am on the home page - And I fill in "User name or email:" with "sam" + And I fill in "Username or email:" with "sam" And I fill in "Password:" with "test" And I press "Log In" - Then I should see "The password or user name you entered doesn't match our records" - And I should see "Forgot your password or user name?" + Then I should see "The password or username you entered doesn't match our records" + And I should see "Forgot your password or username?" When I follow "Reset password" - Then I should see "Please tell us the user name or email address you used when you signed up for your Archive account" - When I fill in "Email address or user name" with "sam" + Then I should see "Please tell us the username or email address you used when you signed up for your Archive account" + When I fill in "Email address or username" with "sam" And I press "Reset Password" Then I should see "Check your email for instructions on how to reset your password." And 1 email should be delivered @@ -26,7 +26,7 @@ Feature: User Authentication # existing password should still work When I am on the homepage - And I fill in "User name or email:" with "sam" + And I fill in "Username or email:" with "sam" And I fill in "Password:" with "secret" And I press "Log In" Then I should see "Hi, sam" @@ -66,14 +66,14 @@ Feature: User Authentication # old password should no longer work When I am on the homepage - And I fill in "User name or email:" with "sam" + And I fill in "Username or email:" with "sam" And I fill in "Password:" with "secret" And I press "Log In" Then I should not see "Hi, sam" # new password should work When I am on the homepage - And I fill in "User name or email:" with "sam" + And I fill in "Username or email:" with "sam" And I fill in "Password:" with "new When I am on the home page And I follow "Forgot password?" - And I fill in "Email address or user name" with "target" + And I fill in "Email address or username" with "target" And I press "Reset Password" Then I should be on the home page And I should see "Password resets are disabled for that user." And 0 emails should be delivered When I follow "Forgot password?" - And I fill in "Email address or user name" with "user@example.com" + And I fill in "Email address or username" with "user@example.com" And I press "Reset Password" Then I should be on the home page And I should see "Password resets are disabled for that user." @@ -289,11 +289,11 @@ Feature: User Authentication | login | password | | admin | adminpassword | When I go to the login page - And I fill in "User name or email" with "admin" + And I fill in "Username or email" with "admin" And I fill in "Password" with "adminpassword" And I press "Log In" Then I should not see "Successfully logged in" - And I should see "The password or user name you entered doesn't match our records." + And I should see "The password or username you entered doesn't match our records." When I am logged in as an admin And I go to the new user password page Then I should be on the homepage diff --git a/features/users/password_compatibility.feature b/features/users/password_compatibility.feature index 278225eab4a..4c121bb25c8 100644 --- a/features/users/password_compatibility.feature +++ b/features/users/password_compatibility.feature @@ -10,7 +10,7 @@ Feature: | login | password | | user1 | password | When I am on the homepage - And I fill in "User name or email:" with "user1" + And I fill in "Username or email:" with "user1" And I fill in "Password:" with "password" And I press "Log In" Then I should see "Successfully logged in." @@ -21,7 +21,7 @@ Feature: | login | password | | user1 | password | When I am on the homepage - And I fill in "User name or email:" with "user1" + And I fill in "Username or email:" with "user1" And I fill in "Password:" with "password" And I press "Log In" Then I should see "Successfully logged in." @@ -32,7 +32,7 @@ Feature: | login | password | | user1 | password | When I am on the homepage - And I fill in "User name or email:" with "user1" + And I fill in "Username or email:" with "user1" And I fill in "Password:" with "password" And I press "Log In" Then I should see "Successfully logged in." diff --git a/features/users/user_create.feature b/features/users/user_create.feature index a0097dca726..2b30a31e480 100644 --- a/features/users/user_create.feature +++ b/features/users/user_create.feature @@ -16,9 +16,9 @@ Feature: Sign Up for a new account Then I should see "" And I should not see "Almost Done!" Examples: - | field | value | error | - | user_registration_login | xx | User name is too short (minimum is 3 characters)| - | user_registration_login | 87151d8ae964d55515cb986d40394f79ca5c8329c07a8e59f2f783cbfbe401f69a780f27277275b7b2 | User name is too long (maximum is 40 characters) | + | field | value | error | + | user_registration_login | xx | Username is too short (minimum is 3 characters)| + | user_registration_login | 87151d8ae964d55515cb986d40394f79ca5c8329c07a8e59f2f783cbfbe401f69a780f27277275b7b2 | Username is too long (maximum is 40 characters) | | user_registration_password | pass | Password is too short (minimum is 6 characters) | | user_registration_password | 87151d8ae964d55515cb986d40394f79ca5c8329c07a8e59f2f783cbfbe401f69a780f27277275b7b2 | Password is too long (maximum is 40 characters) | | user_registration_password_confirmation | password2 | Password confirmation doesn't match | @@ -62,7 +62,7 @@ Feature: Sign Up for a new account When I fill in the sign up form with valid data And I fill in "user_registration_login" with "user1" And I press "Create Account" - Then I should see "User name has already been taken" + Then I should see "Username has already been taken" And I should not see "Almost Done!" Scenario: The user should not be able to sign up with a login that is already in use, no matter the case @@ -72,7 +72,7 @@ Feature: Sign Up for a new account When I fill in the sign up form with valid data And I fill in "user_registration_login" with "USER1" And I press "Create Account" - Then I should see "User name has already been taken" + Then I should see "Username has already been taken" And I should not see "Almost Done!" Scenario: The user should be able to create a new account with a valid email and password diff --git a/features/users/user_rename.feature b/features/users/user_rename.feature index 98c9ee4c587..51180420a08 100644 --- a/features/users/user_rename.feature +++ b/features/users/user_rename.feature @@ -2,22 +2,22 @@ Feature: In order to correct mistakes or reflect my evolving personality As a registered user - I should be able to change my user name + I should be able to change my username Scenario: The user should not be able to change username without a password Given I am logged in as "testuser" with password "password" When I visit the change username page for testuser - And I fill in "New user name" with "anothertestuser" - And I press "Change User Name" + And I fill in "New username" with "anothertestuser" + And I press "Change Username" # TODO - better written error message Then I should see "Your password was incorrect" Scenario: The user should not be able to change their username with an incorrect password Given I am logged in as "testuser" with password "password" When I visit the change username page for testuser - And I fill in "New user name" with "anothertestuser" + And I fill in "New username" with "anothertestuser" And I fill in "Password" with "wrongpwd" - And I press "Change User Name" + And I press "Change Username" Then I should see "Your password was incorrect" Scenario: The user should not be able to change their username to another user's name @@ -27,10 +27,10 @@ Feature: | otheruser | secret | And I am logged in as "downthemall" with password "password" When I visit the change username page for downthemall - And I fill in "New user name" with "otheruser" + And I fill in "New username" with "otheruser" And I fill in "Password" with "password" When I press "Change" - Then I should see "User name has already been taken" + Then I should see "Username has already been taken" Scenario: The user should not be able to change their username to another user's name even if the capitalization is different Given I have no users @@ -39,15 +39,15 @@ Feature: | otheruser | secret | And I am logged in as "downthemall" with password "password" When I visit the change username page for downthemall - And I fill in "New user name" with "OtherUser" + And I fill in "New username" with "OtherUser" And I fill in "Password" with "password" - And I press "Change User Name" - Then I should see "User name has already been taken" + And I press "Change Username" + Then I should see "Username has already been taken" Scenario: The user should be able to change their username if username and password are valid Given I am logged in as "downthemall" with password "password" When I visit the change username page for downthemall - And I fill in "New user name" with "DownThemAll" + And I fill in "New username" with "DownThemAll" And I fill in "Password" with "password" And I press "Change" Then I should get confirmation that I changed my username @@ -56,43 +56,43 @@ Feature: Scenario: The user should be able to change their username to a similar version with underscores Given I am logged in as "downthemall" with password "password" When I visit the change username page for downthemall - And I fill in "New user name" with "Down_Them_All" + And I fill in "New username" with "Down_Them_All" And I fill in "Password" with "password" - And I press "Change User Name" + And I press "Change Username" Then I should get confirmation that I changed my username And I should see "Hi, Down_Them_All!" - Scenario: Changing my user name with one pseud changes that pseud + Scenario: Changing my username with one pseud changes that pseud Given I have no users And I am logged in as "oldusername" with password "password" When I visit the change username page for oldusername - And I fill in "New user name" with "newusername" + And I fill in "New username" with "newusername" And I fill in "Password" with "password" - And I press "Change User Name" + And I press "Change Username" Then I should get confirmation that I changed my username And I should see "Hi, newusername" When I go to my pseuds page Then I should not see "oldusername" When I follow "Edit" - Then I should see "You cannot change the pseud that matches your user name" + Then I should see "You cannot change the pseud that matches your username" Then the "pseud_is_default" checkbox should be checked and disabled - Scenario: Changing only the capitalization of my user name with one pseud changes that pseud's capitalization + Scenario: Changing only the capitalization of my username with one pseud changes that pseud's capitalization Given I have no users And I am logged in as "uppercrust" with password "password" When I visit the change username page for uppercrust - And I fill in "New user name" with "Uppercrust" + And I fill in "New username" with "Uppercrust" And I fill in "Password" with "password" - And I press "Change User Name" + And I press "Change Username" Then I should get confirmation that I changed my username And I should see "Hi, Uppercrust" When I go to my pseuds page Then I should not see "uppercrust" When I follow "Edit" - Then I should see "You cannot change the pseud that matches your user name" + Then I should see "You cannot change the pseud that matches your username" Then the "pseud_is_default" checkbox should be checked and disabled - Scenario: Changing my user name with two pseuds, one same as new, doesn't change old + Scenario: Changing my username with two pseuds, one same as new, doesn't change old Given I have no users And the following activated user exists | login | password | id | @@ -100,9 +100,9 @@ Feature: And a pseud exists with name: "newusername", user_id: 1 And I am logged in as "oldusername" with password "secret" When I visit the change username page for oldusername - And I fill in "New user name" with "newusername" + And I fill in "New username" with "newusername" And I fill in "Password" with "secret" - And I press "Change User Name" + And I press "Change Username" Then I should get confirmation that I changed my username And I should see "Hi, newusername" When I follow "Pseuds (2)" @@ -115,9 +115,9 @@ Feature: And I post a work "Epic story" And I wait 1 second When I visit the change username page for oldusername - And I fill in "New user name" with "newusername" + And I fill in "New username" with "newusername" And I fill in "Password" with "password" - And I press "Change User Name" + And I press "Change Username" And all indexing jobs have been run Then I should get confirmation that I changed my username When I am on the works page @@ -141,9 +141,9 @@ Feature: Then I should see "mine (before)" When it is currently 1 second from now And I visit the change username page for before - And I fill in "New user name" with "after" + And I fill in "New username" with "after" And I fill in "Password" with "password" - And I press "Change User Name" + And I press "Change Username" And I view the work "Interesting" with comments Then I should see "after" within ".comment h4.byline" And I should not see "mine (before)" @@ -190,9 +190,9 @@ Feature: And I follow "Series" Then I should see "Best Series by oldusername" When I visit the change username page for oldusername - And I fill in "New user name" with "newusername" + And I fill in "New username" with "newusername" And I fill in "Password" with "password" - And I press "Change User Name" + And I press "Change Username" Then I should get confirmation that I changed my username And I should see "Hi, newusername" When I follow "Series" @@ -203,12 +203,12 @@ Feature: And the following activated user exists | login | password | | forbidden | secret | - And the user name "forbidden" is on the forbidden list + And the username "forbidden" is on the forbidden list When I am logged in as "forbidden" with password "secret" And I visit the change username page for forbidden - And I fill in "New user name" with "notforbidden" + And I fill in "New username" with "notforbidden" And I fill in "Password" with "secret" - And I press "Change User Name" + And I press "Change Username" Then I should get confirmation that I changed my username And I should see "Hi, notforbidden" @@ -217,17 +217,17 @@ Feature: And I am logged in as "before" with password "password" And all emails have been delivered And I visit the change username page for before - And I fill in "New user name" with "after" + And I fill in "New username" with "after" And I fill in "Password" with "password" - And I press "Change User Name" + And I press "Change Username" Then 0 email should be delivered to "tagwranglers-personnel@example.org" When the user "wrangler_before" exists and has the role "tag_wrangler" And I am logged in as "wrangler_before" with password "password" And all emails have been delivered And I visit the change username page for wrangler_before - And I fill in "New user name" with "wrangler_after" + And I fill in "New username" with "wrangler_after" And I fill in "Password" with "password" - And I press "Change User Name" + And I press "Change Username" Then 1 email should be delivered to "tagwranglers-personnel@example.org" And the email should contain "The wrangler" And the email should contain "wrangler_before" diff --git a/features/works/work_share.feature b/features/works/work_share.feature index 52ed92fab90..590933fb8d4 100644 --- a/features/works/work_share.feature +++ b/features/works/work_share.feature @@ -77,7 +77,7 @@ Feature: Share Works Then I should see "Close" within "#modal" When I follow "Close" And I follow "Log In" - And I fill in "User name or email:" with "maduser" + And I fill in "Username or email:" with "maduser" And I fill in "Password:" with "password" And I press "Log In" Then the url should not include "share" diff --git a/spec/controllers/pseuds_controller_spec.rb b/spec/controllers/pseuds_controller_spec.rb index 5f39b04b0bd..a403afc7e23 100644 --- a/spec/controllers/pseuds_controller_spec.rb +++ b/spec/controllers/pseuds_controller_spec.rb @@ -212,7 +212,7 @@ matching_pseud.reload post :destroy, params: { user_id: user, id: matching_pseud } - it_redirects_to_with_error(user_pseuds_path(user), "You cannot delete the pseud matching your user name, sorry!") + it_redirects_to_with_error(user_pseuds_path(user), "You cannot delete the pseud matching your username, sorry!") end end end diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb index c753700f0d3..2735a476132 100644 --- a/spec/controllers/users_controller_spec.rb +++ b/spec/controllers/users_controller_spec.rb @@ -4,6 +4,43 @@ include RedirectExpectationHelper include LoginMacros + shared_examples "an action only authorized admins can access" do |authorized_roles:| + before do + fake_login_admin(admin) + end + + context "when logged in as an admin with no role" do + let(:admin) { create(:admin) } + + it "redirects with an error" do + subject + 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 - authorized_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 + subject + it_redirects_to_with_error(root_url, "Sorry, only an authorized admin can access the page you were trying to reach.") + end + end + end + + authorized_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 "succeeds" do + subject + success + end + end + end + end + shared_examples "blocks access for banned and suspended users" do context "when logged in as a banned user" do let(:user) { create(:user, banned: true) } @@ -91,39 +128,60 @@ end describe "GET #change_username" do + let(:user) { create(:user) } + let(:success) { expect(response).to render_template(:change_username) } subject { get :change_username, params: { id: user } } context "when logged in as a valid user" do - let(:user) { create(:user) } - before do fake_login_known_user(user) end it "shows the change username form" do subject - expect(response).to render_template(:change_username) + success end end + it_behaves_like "an action only authorized admins can access", authorized_roles: %w[superadmin policy_and_abuse] it_behaves_like "blocks access for banned and suspended users" end describe "POST #changed_username" do + let(:user) { create(:user) } + let(:new_username) { "foo1234" } + let(:success) do + expect(user.reload.login).to eq(new_username) + end + subject do - post :changed_username, params: { id: user, new_login: "foo1234", password: user.password } + post :changed_username, params: { id: user, new_login: new_username, password: user.password } end context "when logged in as a valid user" do - let(:user) { create(:user) } - before do fake_login_known_user(user) end it "updates the user's username" do - expect { subject } - .to change { user.reload.login } + subject + success + end + end + + it_behaves_like "an action only authorized admins can access", authorized_roles: %w[superadmin policy_and_abuse] do + let(:user) { create(:user, banned: true) } + let(:new_username) { "user#{user.id}" } + + before do + allow_any_instance_of(ZohoResourceClient).to receive(:find_ticket).and_return({ + "status" => "Open", + "departmentId" => "" + }) + end + + subject do + post :changed_username, params: { id: user, new_login: new_username, ticket_number: 123 } end end diff --git a/spec/models/admin_spec.rb b/spec/models/admin_spec.rb index 99a268cd310..ddd85fc9985 100644 --- a/spec/models/admin_spec.rb +++ b/spec/models/admin_spec.rb @@ -30,7 +30,7 @@ end context "invalid" do - it "without a user name" do + it "without a username" do expect { create(:admin, login: nil) } .to raise_error(ActiveRecord::RecordInvalid, "Validation failed: Login can't be blank, Login is too short (minimum is #{ArchiveConfig.LOGIN_LENGTH_MIN} characters)") diff --git a/spec/models/concerns/justifiable_spec.rb b/spec/models/concerns/justifiable_spec.rb index b023e56a6f0..0a27d95f120 100644 --- a/spec/models/concerns/justifiable_spec.rb +++ b/spec/models/concerns/justifiable_spec.rb @@ -129,3 +129,12 @@ let(:attributes) { { description: "Edited by admin." } } end end + +describe User do + context "when login is changed" do + it_behaves_like "a justifiable model" do + let!(:record) { create(:user) } + let(:attributes) { { login: "user#{record.id}" } } + end + end +end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index ab0bb71f177..9b468e5e898 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -196,6 +196,51 @@ describe "#update" do let!(:existing_user) { create(:user) } + context "when logged in as an admin" do + before do + User.current_user = build(:admin) + end + + context "when username is changed" do + before do + allow(existing_user).to receive(:justification_enabled?).and_return(false) + allow(existing_user).to receive(:ticket_number).and_return(12_345) + end + + it "requires the default format" do + existing_user.update(login: "custom_username") + expect(existing_user.errors[:login].first).to eq "must use the default. Please contact your chairs to use something else." + end + + it "does not set renamed_at" do + existing_user.update!(login: "user#{existing_user.id}") + expect(existing_user.renamed_at).to be nil + end + + it "creates an admin log item" do + old_login = existing_user.login + existing_user.update!(login: "user#{existing_user.id}") + log_item = existing_user.reload.log_items.last + admin = User.current_user + expect(log_item.action).to eq(ArchiveConfig.ACTION_RENAME) + expect(log_item.admin_id).to eq(admin.id) + expect(log_item.note).to eq("Old Username: #{old_login}, New Username: #{existing_user.login}, Changed by: #{admin.login}, Ticket ID: #12345") + end + end + + context "username was recently changed" do + before do + existing_user.update!(renamed_at: Time.current) + end + + it "does not prevent changing the username" do + allow(existing_user).to receive(:justification_enabled?).and_return(false) + existing_user.update!(login: "user#{existing_user.id}") + expect(existing_user.login).to eq("user#{existing_user.id}") + end + end + end + it "sets renamed_at if username is changed" do freeze_time existing_user.update!(login: "new_username") @@ -213,7 +258,7 @@ .to raise_error(ActiveRecord::RecordInvalid) localized_renamed_at = I18n.l(existing_user.renamed_at, format: :long) expect(existing_user.errors[:login].first).to eq( - "can only be changed once every 7 days. You last changed your user name on #{localized_renamed_at}." + "can only be changed once every 7 days. You last changed your username on #{localized_renamed_at}." ) end
    <%= t(".invitation_information") %>
    <%= t(".token") %><%= t(".sent_to") %><%= t(".username") %><%= t(".external_author") %><%= t(".copy_link") %>
    <%= link_to invitation.token, (invitation.creator.is_a?(User) ? [invitation.creator, invitation] : invitation) %> <%= invitation.invitee_email %><%=invitee_link(invitation) %><%= invitation.external_author ? "#{invitation.external_author.email} (#{invitation.external_author.names.collect(&:name).delete_if {|name| name == invitation.external_author.email}.join(",")})" : "" %><%= invitee_link(invitation) %> + <%= invitation.external_author ? "#{invitation.external_author.email} (#{invitation.external_author.names.collect(&:name).delete_if { |name| name == invitation.external_author.email } +.join(',')})" : "" %> + <% unless invitation.redeemed_at %> <% if invitation.external_author %> - <%= link_to ts("copy and use"), claim_path(:invitation_token => invitation.token) %> + <%= link_to t(".copy_and_use"), claim_path(invitation_token: invitation.token) %> <% else %> - <%= link_to ts("copy and use"), signup_path(:invitation_token => invitation.token) %><% end %> + <%= link_to t(".copy_and_use"), signup_path(invitation_token: invitation.token) %><% end %> <% end %> <%= link_to("Delete", invitation, data: {confirm: "Are you sure you want to delete this invitation?"}, :method => :delete) %><%= link_to(t(".delete"), invitation, data: { confirm: t(".delete_confirmation") }, method: :delete) %>