diff --git a/app/controllers/users/registrations_controller.rb b/app/controllers/users/registrations_controller.rb index a6f6967..7c17f43 100644 --- a/app/controllers/users/registrations_controller.rb +++ b/app/controllers/users/registrations_controller.rb @@ -59,18 +59,18 @@ def update protected def configure_permitted_parameters - devise_parameter_sanitizer.permit(:sign_up, keys: [:email, :password, :password_confirmation, :username, :full_name, :tags, :avatar, :banner, :description, :banner_enabled]) - devise_parameter_sanitizer.permit(:account_update, keys: [:email, :password, :password_confirmation, :username, :full_name, :tags, :avatar, :banner, :description, :banner_enabled]) + devise_parameter_sanitizer.permit(:sign_up, keys: [:email, :password, :password_confirmation, :username, :full_name, :tags, :avatar, :banner, :description, :banner_enabled, :avatar_border]) + devise_parameter_sanitizer.permit(:account_update, keys: [:email, :password, :password_confirmation, :username, :full_name, :tags, :avatar, :banner, :description, :banner_enabled, :avatar_border]) end def sign_up_params - params.require(:user).permit(:email, :password, :password_confirmation, :username, :full_name, :tags, :avatar, :banner, :description, :banner_enabled).tap do |user_params| + params.require(:user).permit(:email, :password, :password_confirmation, :username, :full_name, :tags, :avatar, :banner, :description, :banner_enabled, :avatar_border).tap do |user_params| user_params[:tags] = user_params[:tags].split(',').map(&:strip).to_json if user_params[:tags].present? end end def account_update_params - params.require(:user).permit(:email, :password, :password_confirmation, :current_password, :username, :full_name, :tags, :avatar, :banner, :description, :banner_enabled, :public_analytics).tap do |user_params| + params.require(:user).permit(:email, :password, :password_confirmation, :current_password, :username, :full_name, :tags, :avatar, :banner, :description, :banner_enabled, :public_analytics, :avatar_border).tap do |user_params| user_params[:tags] = user_params[:tags].split(',').map(&:strip).to_json if user_params[:tags].present? end end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index cc5765d..501edf1 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -5,6 +5,17 @@ def auto_link_urls(text) end.html_safe end + def avatar_border_class(border_preference) + case border_preference + when 'white' + 'border-4 border-white' + when 'black' + 'border-4 border-black' + else + '' + end + end + def format_referrer(referrer) return 'Direct' if referrer.blank? diff --git a/app/models/user.rb b/app/models/user.rb index d5ef75e..ea8298e 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -14,6 +14,7 @@ class User < ApplicationRecord validates :username, uniqueness: true, allow_blank: true validates :full_name, presence: true validate :ensure_username_presence + validates :avatar_border, inclusion: { in: ['white', 'black', 'none'] } after_save :generate_open_graph_image, unless: -> { Rails.env.test? } after_save :download_and_store_avatar diff --git a/app/views/devise/registrations/edit.html.erb b/app/views/devise/registrations/edit.html.erb index e25531c..bf6c2e6 100644 --- a/app/views/devise/registrations/edit.html.erb +++ b/app/views/devise/registrations/edit.html.erb @@ -1,80 +1,90 @@ -

Edit <%= resource_name.to_s.humanize %>

- -<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %> - <%= devise_error_messages! %> - -
- <%= f.label :email, class: 'block text-gray-300 mb-1' %> - <%= f.email_field :email, autofocus: true, class: 'w-full p-1 rounded text-black' %> -
- -
- <%= f.label :username, class: 'block text-gray-300 mb-1' %> - <%= f.text_field :username, class: 'w-full p-1 rounded text-black' %> -
- -
- <%= f.label :full_name, class: 'block text-gray-300 mb-1' %> - <%= f.text_field :full_name, class: 'w-full p-1 rounded text-black' %> -
- -
- <%= f.label :tags, class: 'block text-gray-300 mb-1' %> - <%= f.text_field :tags, value: @user.parsed_tags.join(', '), class: 'w-full p-1 rounded text-black' %> -
- -
- <%= f.label :avatar, class: 'block text-gray-300 mb-1' %> - <%= f.text_field :avatar, class: 'w-full p-1 rounded text-black' %> -
- -
- <%= f.label :banner, class: 'block text-gray-300 mb-1' %> - <%= f.text_field :banner, class: 'w-full p-1 rounded text-black' %> -
- -
- <%= f.label :banner_enabled, class: 'block text-gray-300 mb-1' %> - <%= f.check_box :banner_enabled, class: 'rounded text-black' %> +
+

Edit <%= resource_name.to_s.humanize %>

+ + <%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put, class: "space-y-6" }) do |f| %> + <%= devise_error_messages! %> + +
+ <%= f.label :email, class: 'block text-lime-200 font-semibold mb-2' %> + <%= f.email_field :email, autofocus: true, class: 'block w-full px-4 py-2 border border-gray-700 rounded bg-gray-900 text-white focus:outline-none focus:border-lime-500' %> +
+ +
+ <%= f.label :username, class: 'block text-lime-200 font-semibold mb-2' %> + <%= f.text_field :username, class: 'block w-full px-4 py-2 border border-gray-700 rounded bg-gray-900 text-white focus:outline-none focus:border-lime-500' %> +
+ +
+ <%= f.label :full_name, class: 'block text-lime-200 font-semibold mb-2' %> + <%= f.text_field :full_name, class: 'block w-full px-4 py-2 border border-gray-700 rounded bg-gray-900 text-white focus:outline-none focus:border-lime-500' %> +
+ +
+ <%= f.label :tags, class: 'block text-lime-200 font-semibold mb-2' %> + <%= f.text_field :tags, value: @user.parsed_tags.join(', '), class: 'block w-full px-4 py-2 border border-gray-700 rounded bg-gray-900 text-white focus:outline-none focus:border-lime-500' %> +
+ +
+ <%= f.label :avatar, class: 'block text-lime-200 font-semibold mb-2' %> + <%= f.text_field :avatar, class: 'block w-full px-4 py-2 border border-gray-700 rounded bg-gray-900 text-white focus:outline-none focus:border-lime-500' %> +
+ +
+ <%= f.label :avatar_border, class: 'block text-lime-200 font-semibold mb-2' %> + <%= f.select :avatar_border, options_for_select([['White', 'white'], ['Black', 'black'], ['None', 'none']], @user.avatar_border), {}, class: 'block w-full px-4 py-2 border border-gray-700 rounded bg-gray-900 text-white focus:outline-none focus:border-lime-500' %> +
+ +
+ <%= f.label :banner, class: 'block text-lime-200 font-semibold mb-2' %> + <%= f.text_field :banner, class: 'block w-full px-4 py-2 border border-gray-700 rounded bg-gray-900 text-white focus:outline-none focus:border-lime-500' %> +
+ +
+ <%= f.check_box :banner_enabled, class: 'mr-2' %> + <%= f.label :banner_enabled, class: 'text-lime-200 font-semibold' %> +
+ +
+ <%= f.label :description, class: 'block text-lime-200 font-semibold mb-2' %> + <%= f.text_area :description, rows: 3, class: 'block w-full px-4 py-2 border border-gray-700 rounded bg-gray-900 text-white focus:outline-none focus:border-lime-500' %> +
+ +
+ <%= f.check_box :public_analytics, class: 'mr-2' %> + <%= f.label :public_analytics, class: 'text-lime-200 font-semibold' %> +
+ +
+ <%= f.label :password, class: 'block text-lime-200 font-semibold mb-2' %> + <%= f.password_field :password, autocomplete: "off", class: 'block w-full px-4 py-2 border border-gray-700 rounded bg-gray-900 text-white focus:outline-none focus:border-lime-500' %> + <% if @minimum_password_length %> +

<%= @minimum_password_length %> characters minimum (leave blank if you don't want to change it)

+ <% end %> +
+ +
+ <%= f.label :password_confirmation, class: 'block text-lime-200 font-semibold mb-2' %> + <%= f.password_field :password_confirmation, autocomplete: "off", class: 'block w-full px-4 py-2 border border-gray-700 rounded bg-gray-900 text-white focus:outline-none focus:border-lime-500' %> +
+ +
+ <%= f.label :current_password, class: 'block text-lime-200 font-semibold mb-2' %> + <%= f.password_field :current_password, autocomplete: "off", class: 'block w-full px-4 py-2 border border-gray-700 rounded bg-gray-900 text-white focus:outline-none focus:border-lime-500' %> +

We need your current password to confirm your changes

+
+ +
+ <%= f.submit "Update", class: 'bg-lime-500 hover:bg-lime-600 text-white font-bold py-2 px-4 rounded-sm text-sm uppercase tracking-wide transition duration-300 ease-in-out focus:outline-none' %> +
+ <% end %> + +
+

Cancel my account

+

Unhappy? You can cancel your account here.

+ <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure? This action cannot be undone." }, method: :delete, class: 'bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded transition duration-300 ease-in-out' %>
-
- <%= f.label :description, class: 'block text-gray-300 mb-1' %> - <%= f.text_area :description, class: 'w-full p-1 rounded text-black' %> +
+ <%= link_to "Back", :back, class: 'text-lime-300 hover:text-lime-500 underline transition duration-300 ease-in-out' %>
- -
- <%= f.label :public_analytics %> - <%= f.check_box :public_analytics %> -
- -
- <%= f.label :password, class: 'block text-gray-300 mb-1' %> - <% if @minimum_password_length %> - (<%= @minimum_password_length %> characters minimum) - <% end %> - <%= f.password_field :password, autocomplete: "off", class: 'w-full p-1 rounded text-black' %> - (leave blank if you don't want to change it) -
- -
- <%= f.label :password_confirmation, class: 'block text-gray-300 mb-1' %> - <%= f.password_field :password_confirmation, autocomplete: "off", class: 'w-full p-1 rounded text-black' %> -
- -
- <%= f.label :current_password, class: 'block text-gray-300 mb-1' %> - <%= f.password_field :current_password, autocomplete: "off", class: 'w-full p-1 rounded text-black' %> - (we need your current password to confirm your changes) -
- -
- <%= f.submit "Update", class: 'bg-lime-500 hover:bg-lime-700 text-white font-bold py-1 px-2 rounded' %> -
-<% end %> - -

Cancel my account

- -

Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete, class: 'bg-red-500 hover:bg-red-700 text-white font-bold py-1 px-2 rounded' %>

- -<%= link_to "Back", :back, class: 'bg-gray-500 hover:bg-gray-700 text-white font-bold py-1 px-2 rounded' %> +
\ No newline at end of file diff --git a/app/views/links/user_links.html.erb b/app/views/links/user_links.html.erb index 17808e1..b08ed63 100644 --- a/app/views/links/user_links.html.erb +++ b/app/views/links/user_links.html.erb @@ -7,16 +7,17 @@
<% end %>
-
- <% local_avatar_path = "/avatars/#{@user.username}_avatar#{File.extname(@user.avatar)}" %> - <% if File.exist?(Rails.root.join('public' + local_avatar_path)) %> - <%= image_tag local_avatar_path, alt: @user.email, class: "rounded-full border-4 border-gray-900 object-cover", style: "width: 8rem; height: 8rem;" %> - <% elsif @user.avatar.present? %> - <%= image_tag @user.avatar, alt: @user.email, class: "rounded-full border-4 border-gray-900 object-cover", style: "width: 8rem; height: 8rem;" %> - <% else %> - <%= image_tag "greg.jpg", alt: @user.email, class: "rounded-full border-4 border-gray-900 object-cover", style: "width: 8rem; height: 8rem;" %> - <% end %> -
+
+ <% local_avatar_path = "/avatars/#{@user.username}_avatar#{File.extname(@user.avatar)}" %> + <% if File.exist?(Rails.root.join('public' + local_avatar_path)) %> + <%= image_tag local_avatar_path, alt: @user.email, class: "rounded-full object-cover #{avatar_border_class(@user.avatar_border)}", style: "width: 8rem; height: 8rem;" %> + <% elsif @user.avatar.present? %> + <%= image_tag @user.avatar, alt: @user.email, class: "rounded-full object-cover #{avatar_border_class(@user.avatar_border)}", style: "width: 8rem; height: 8rem;" %> + <% else %> + <%= image_tag "greg.jpg", alt: @user.email, class: "rounded-full object-cover #{avatar_border_class(@user.avatar_border)}", style: "width: 8rem; height: 8rem;" %> + <% end %> +
+

<%= @user.full_name %>

<%= @user.username %>

@@ -39,7 +40,7 @@
<% end %> -
+

<%= auto_link_urls(@user.description) %>

diff --git a/db/migrate/20240902002819_add_avatar_border_to_users.rb b/db/migrate/20240902002819_add_avatar_border_to_users.rb new file mode 100644 index 0000000..d57608b --- /dev/null +++ b/db/migrate/20240902002819_add_avatar_border_to_users.rb @@ -0,0 +1,5 @@ +class AddAvatarBorderToUsers < ActiveRecord::Migration[7.1] + def change + add_column :users, :avatar_border, :string, default: 'white' + end +end diff --git a/db/schema.rb b/db/schema.rb index 5064c64..02c5548 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2024_09_01_125227) do +ActiveRecord::Schema[7.1].define(version: 2024_09_02_002819) do create_table "achievement_views", force: :cascade do |t| t.integer "achievement_id", null: false t.integer "user_id", null: false @@ -135,6 +135,7 @@ t.string "tags", default: "[]" t.boolean "public_analytics", default: false t.boolean "banner_enabled", default: true + t.string "avatar_border" t.index ["email"], name: "index_users_on_email", unique: true t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true t.index ["username"], name: "index_users_on_username", unique: true diff --git a/spec/controllers/users/registrations_controller_spec.rb b/spec/controllers/users/registrations_controller_spec.rb index 56ba840..5fddefd 100644 --- a/spec/controllers/users/registrations_controller_spec.rb +++ b/spec/controllers/users/registrations_controller_spec.rb @@ -1,4 +1,3 @@ -# spec/controllers/users/registrations_controller_spec.rb require 'rails_helper' RSpec.describe Users::RegistrationsController, type: :controller do @@ -9,7 +8,7 @@ describe "POST #create" do let(:valid_attributes) { { email: "test@example.com", password: "password", password_confirmation: "password", - username: "testuser", full_name: "Test User", tags: "tag1,tag2" } + username: "testuser", full_name: "Test User", tags: "tag1,tag2", avatar_border: "white" } } it "creates a new User" do @@ -35,7 +34,7 @@ context "with valid params" do let(:new_attributes) { - { full_name: "New Name", tags: "new_tag1,new_tag2" } + { full_name: "New Name", tags: "new_tag1,new_tag2", avatar_border: "black" } } it "updates the requested user" do @@ -44,6 +43,7 @@ expect(user.full_name).to eq("New Name") tags = user.tags.is_a?(String) ? JSON.parse(user.tags) : user.tags expect(tags).to eq(["new_tag1", "new_tag2"]) + expect(user.avatar_border).to eq("black") end end end diff --git a/spec/factories/users.rb b/spec/factories/users.rb index 49b66d0..6339d72 100644 --- a/spec/factories/users.rb +++ b/spec/factories/users.rb @@ -1,4 +1,3 @@ -# spec/factories/users.rb FactoryBot.define do factory :user do sequence(:email) { |n| "user#{n}@example.com" } @@ -6,6 +5,7 @@ password_confirmation { "password123" } sequence(:username) { |n| "user#{n}" } full_name { "Test User" } - tags { ["tag1", "tag2"] } + tags { ["tag1", "tag2"].to_json } + avatar_border { ['white', 'black', 'none'].sample } end end \ No newline at end of file