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