mirror of
https://github.com/System-End/hackatime.git
synced 2026-04-19 23:32:53 +00:00
Add custom name support (#579)
This commit is contained in:
parent
c0d2f412c5
commit
630177cf4a
19 changed files with 153 additions and 68 deletions
|
|
@ -135,7 +135,7 @@ class Admin::TimelineController < Admin::BaseController
|
|||
|
||||
# For Stimulus: provide initial selected users with details
|
||||
@initial_selected_user_objects = User.where(id: @selected_user_ids)
|
||||
.select(:id, :username, :slack_username, :github_username, :slack_avatar_url, :github_avatar_url)
|
||||
.select(:id, :custom_name, :slack_username, :github_username, :slack_avatar_url, :github_avatar_url)
|
||||
.map { |u| { id: u.id, display_name: "#{u.display_name}", avatar_url: u.avatar_url } }
|
||||
.sort_by { |u_obj| @selected_user_ids.index(u_obj[:id]) || Float::INFINITY } # Preserve order
|
||||
|
||||
|
|
@ -185,10 +185,10 @@ class Admin::TimelineController < Admin::BaseController
|
|||
avatar_url: user_id_match.avatar_url
|
||||
} ]
|
||||
else
|
||||
users = User.where("LOWER(username) LIKE :query OR LOWER(slack_username) LIKE :query OR CAST(id AS TEXT) LIKE :query OR EXISTS (SELECT 1 FROM email_addresses WHERE email_addresses.user_id = users.id AND LOWER(email_addresses.email) LIKE :query)", query: "%#{query_term}%")
|
||||
.order(Arel.sql("CASE WHEN LOWER(username) = #{ActiveRecord::Base.connection.quote(query_term)} THEN 0 ELSE 1 END, username ASC")) # Prioritize exact match
|
||||
users = User.where("LOWER(custom_name) LIKE :query OR LOWER(slack_username) LIKE :query OR CAST(id AS TEXT) LIKE :query OR EXISTS (SELECT 1 FROM email_addresses WHERE email_addresses.user_id = users.id AND LOWER(email_addresses.email) LIKE :query)", query: "%#{query_term}%")
|
||||
.order(Arel.sql("CASE WHEN LOWER(custom_name) = #{ActiveRecord::Base.connection.quote(query_term)} THEN 0 ELSE 1 END, username ASC")) # Prioritize exact match
|
||||
.limit(20)
|
||||
.select(:id, :username, :slack_username, :github_username, :slack_avatar_url, :github_avatar_url)
|
||||
.select(:id, :custom_name, :slack_username, :github_username, :slack_avatar_url, :github_avatar_url)
|
||||
|
||||
results = users.map do |user|
|
||||
{
|
||||
|
|
@ -218,7 +218,7 @@ class Admin::TimelineController < Admin::BaseController
|
|||
all_ids_to_fetch.unshift(current_user.id).uniq!
|
||||
|
||||
users_data = User.where(id: all_ids_to_fetch)
|
||||
.select(:id, :username, :slack_username, :github_username, :slack_avatar_url, :github_avatar_url)
|
||||
.select(:id, :custom_name, :slack_username, :github_username, :slack_avatar_url, :github_avatar_url)
|
||||
.index_by(&:id)
|
||||
|
||||
final_user_objects = []
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ class Admin::TrustLevelAuditLogsController < Admin::BaseController
|
|||
if params[:user_search].present?
|
||||
search_term = params[:user_search].strip
|
||||
user_ids = User.joins(:email_addresses)
|
||||
.where("LOWER(users.username) LIKE ? OR LOWER(users.slack_username) LIKE ? OR LOWER(users.github_username) LIKE ? OR LOWER(email_addresses.email) LIKE ? OR CAST(users.id AS TEXT) LIKE ?",
|
||||
.where("LOWER(users.custom_name) LIKE ? OR LOWER(users.slack_username) LIKE ? OR LOWER(users.github_username) LIKE ? OR LOWER(email_addresses.email) LIKE ? OR CAST(users.id AS TEXT) LIKE ?",
|
||||
"%#{search_term.downcase}%", "%#{search_term.downcase}%", "%#{search_term.downcase}%", "%#{search_term.downcase}%", "%#{search_term}%")
|
||||
.pluck(:id)
|
||||
@audit_logs = @audit_logs.where(user_id: user_ids)
|
||||
|
|
@ -35,7 +35,7 @@ class Admin::TrustLevelAuditLogsController < Admin::BaseController
|
|||
if params[:admin_search].present?
|
||||
search_term = params[:admin_search].strip
|
||||
admin_ids = User.joins(:email_addresses)
|
||||
.where("LOWER(users.username) LIKE ? OR LOWER(users.slack_username) LIKE ? OR LOWER(users.github_username) LIKE ? OR LOWER(email_addresses.email) LIKE ? OR CAST(users.id AS TEXT) LIKE ?",
|
||||
.where("LOWER(users.custom_name) LIKE ? OR LOWER(users.slack_username) LIKE ? OR LOWER(users.github_username) LIKE ? OR LOWER(email_addresses.email) LIKE ? OR CAST(users.id AS TEXT) LIKE ?",
|
||||
"%#{search_term.downcase}%", "%#{search_term.downcase}%", "%#{search_term.downcase}%", "%#{search_term.downcase}%", "%#{search_term}%")
|
||||
.pluck(:id)
|
||||
@audit_logs = @audit_logs.where(changed_by_id: admin_ids)
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ module Api
|
|||
},
|
||||
creator: {
|
||||
id: creator.id,
|
||||
username: creator.username,
|
||||
username: creator.custom_name,
|
||||
display_name: creator.display_name,
|
||||
admin_level: creator.admin_level
|
||||
}
|
||||
|
|
@ -75,7 +75,7 @@ module Api
|
|||
render json: {
|
||||
user: {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
username: user.custom_name,
|
||||
display_name: user.display_name,
|
||||
slack_uid: user.slack_uid,
|
||||
slack_username: user.slack_username,
|
||||
|
|
@ -118,7 +118,7 @@ module Api
|
|||
|
||||
render json: {
|
||||
user_id: user.id,
|
||||
username: user.username,
|
||||
username: user.display_name,
|
||||
date: date.iso8601,
|
||||
timezone: user.timezone,
|
||||
heartbeats: heartbeats.map do |hb|
|
||||
|
|
@ -184,7 +184,7 @@ module Api
|
|||
|
||||
render json: {
|
||||
user_id: user.id,
|
||||
username: user.username,
|
||||
username: user.display_name,
|
||||
projects: project_data,
|
||||
total_projects: project_data.count
|
||||
}
|
||||
|
|
@ -223,12 +223,12 @@ module Api
|
|||
message: "gotcha, updated to #{trust_level}",
|
||||
user: {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
username: user.display_name,
|
||||
trust_level: user.trust_level,
|
||||
updated_at: user.updated_at
|
||||
},
|
||||
audit_log: {
|
||||
changed_by: current_user.username,
|
||||
changed_by: current_user.display_name,
|
||||
reason: reason,
|
||||
notes: notes,
|
||||
timestamp: Time.current
|
||||
|
|
@ -276,7 +276,7 @@ module Api
|
|||
columns: columns,
|
||||
rows: rows,
|
||||
row_count: rows.count,
|
||||
executed_by: current_user.username,
|
||||
executed_by: current_user.display_name,
|
||||
executed_at: Time.current
|
||||
}
|
||||
rescue => e
|
||||
|
|
@ -299,7 +299,7 @@ module Api
|
|||
new_trust_level: log.new_trust_level,
|
||||
changed_by: {
|
||||
id: log.changed_by.id,
|
||||
username: log.changed_by.username,
|
||||
username: log.changed_by.name,
|
||||
display_name: log.changed_by.display_name,
|
||||
admin_level: log.changed_by.admin_level
|
||||
},
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ module Api
|
|||
if user.persisted?
|
||||
return render json: {
|
||||
user_id: user.id,
|
||||
username: user.username,
|
||||
username: user.display_name,
|
||||
email: user.email_addresses.first&.email
|
||||
}, status: :ok
|
||||
end
|
||||
|
|
@ -46,7 +46,7 @@ module Api
|
|||
if user.save
|
||||
render json: {
|
||||
user_id: user.id,
|
||||
username: user.username,
|
||||
username: user.display_name,
|
||||
email: email
|
||||
}, status: :created
|
||||
else
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@ class SessionsController < ApplicationController
|
|||
|
||||
session[:impersonater_user_id] ||= current_user.id
|
||||
session[:user_id] = user.id
|
||||
redirect_to root_path, notice: "Impersonating #{user.username}"
|
||||
redirect_to root_path, notice: "Impersonating #{user.display_name}"
|
||||
end
|
||||
|
||||
def stop_impersonating
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ class StaticPagesController < ApplicationController
|
|||
json_response = locals[:users].map do |user|
|
||||
{
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
username: user.display_name,
|
||||
slack_username: user.slack_username,
|
||||
github_username: user.github_username,
|
||||
display_name: user.display_name,
|
||||
|
|
|
|||
|
|
@ -6,17 +6,7 @@ class UsersController < ApplicationController
|
|||
before_action :require_admin, only: [ :update_trust_level ]
|
||||
|
||||
def edit
|
||||
@can_enable_slack_status = @user.slack_access_token.present? && @user.slack_scopes.include?("users.profile:write")
|
||||
|
||||
@enabled_sailors_logs = SailorsLogNotificationPreference.where(
|
||||
slack_uid: @user.slack_uid,
|
||||
enabled: true,
|
||||
).where.not(slack_channel_id: SailorsLog::DEFAULT_CHANNELS)
|
||||
|
||||
@heartbeats_migration_jobs = @user.data_migration_jobs
|
||||
|
||||
@projects = @user.project_repo_mappings.distinct.pluck(:project_name)
|
||||
@work_time_stats_url = "https://hackatime-badge.hackclub.com/#{@user.slack_uid}/#{@projects.first || 'example'}"
|
||||
prepare_settings_page
|
||||
end
|
||||
|
||||
def update
|
||||
|
|
@ -29,8 +19,9 @@ class UsersController < ApplicationController
|
|||
redirect_to is_own_settings? ? my_settings_path : settings_user_path(@user),
|
||||
notice: "Settings updated successfully"
|
||||
else
|
||||
flash[:error] = "Failed to update settings"
|
||||
render :settings, status: :unprocessable_entity
|
||||
flash.now[:error] = @user.errors.full_messages.to_sentence.presence || "Failed to update settings"
|
||||
prepare_settings_page
|
||||
render :edit, status: :unprocessable_entity
|
||||
end
|
||||
elsif params[:default_timezone_leaderboard].present?
|
||||
if @user.update(default_timezone_leaderboard: params[:default_timezone_leaderboard] == "1")
|
||||
|
|
@ -126,6 +117,21 @@ class UsersController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def prepare_settings_page
|
||||
@is_own_settings = is_own_settings?
|
||||
@can_enable_slack_status = @user.slack_access_token.present? && @user.slack_scopes.include?("users.profile:write")
|
||||
|
||||
@enabled_sailors_logs = SailorsLogNotificationPreference.where(
|
||||
slack_uid: @user.slack_uid,
|
||||
enabled: true,
|
||||
).where.not(slack_channel_id: SailorsLog::DEFAULT_CHANNELS)
|
||||
|
||||
@heartbeats_migration_jobs = @user.data_migration_jobs
|
||||
|
||||
@projects = @user.project_repo_mappings.distinct.pluck(:project_name)
|
||||
@work_time_stats_url = "https://hackatime-badge.hackclub.com/#{@user.slack_uid}/#{@projects.first || 'example'}"
|
||||
end
|
||||
|
||||
def set_user
|
||||
@user = if params["id"].present?
|
||||
User.find(params["id"])
|
||||
|
|
@ -141,6 +147,13 @@ class UsersController < ApplicationController
|
|||
end
|
||||
|
||||
def user_params
|
||||
params.require(:user).permit(:uses_slack_status, :hackatime_extension_text_type, :timezone, :allow_public_stats_lookup, :default_timezone_leaderboard)
|
||||
params.require(:user).permit(
|
||||
:uses_slack_status,
|
||||
:hackatime_extension_text_type,
|
||||
:timezone,
|
||||
:allow_public_stats_lookup,
|
||||
:default_timezone_leaderboard,
|
||||
:custom_name,
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
4
app/jobs/cache/currently_hacking_job.rb
vendored
4
app/jobs/cache/currently_hacking_job.rb
vendored
|
|
@ -29,9 +29,7 @@ class Cache::CurrentlyHackingJob < Cache::ActivityJob
|
|||
users = users.sort_by do |user|
|
||||
[
|
||||
active_projects[user.id].present? ? 0 : 1,
|
||||
user.username.present? ? 0 : 1,
|
||||
user.slack_username.present? ? 0 : 1,
|
||||
user.github_username.present? ? 0 : 1
|
||||
user.display_name.present? ? 0 : 1
|
||||
]
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -2,15 +2,23 @@ class User < ApplicationRecord
|
|||
include TimezoneRegions
|
||||
include PublicActivity::Model
|
||||
|
||||
CUSTOM_NAME_MAX_LENGTH = 21 # going over 21 overflows the navbar
|
||||
|
||||
has_paper_trail
|
||||
|
||||
after_create :create_signup_activity
|
||||
before_validation :normalize_custom_name
|
||||
encrypts :slack_access_token, :github_access_token
|
||||
|
||||
validates :slack_uid, uniqueness: true, allow_nil: true
|
||||
validates :github_uid, uniqueness: { conditions: -> { where.not(github_access_token: nil) } }, allow_nil: true
|
||||
validates :timezone, inclusion: { in: TZInfo::Timezone.all_identifiers }, allow_nil: false
|
||||
validates :country_code, inclusion: { in: ISO3166::Country.codes }, allow_nil: true
|
||||
validates :custom_name,
|
||||
length: { maximum: CUSTOM_NAME_MAX_LENGTH },
|
||||
format: { with: /\A[A-Za-z0-9_-]+\z/, message: "may only include letters, numbers, '-', and '_'" },
|
||||
allow_nil: true
|
||||
validate :custom_name_must_be_visible
|
||||
|
||||
attribute :allow_public_stats_lookup, :boolean, default: true
|
||||
attribute :default_timezone_leaderboard, :boolean, default: true
|
||||
|
|
@ -235,15 +243,13 @@ class User < ApplicationRecord
|
|||
|
||||
return unless user_data.present?
|
||||
|
||||
profile = user_data.dig("profile")
|
||||
profile = user_data["profile"] || {}
|
||||
|
||||
self.slack_avatar_url = profile.dig("image_192") || profile.dig("image_72")
|
||||
self.slack_avatar_url = profile["image_192"] || profile["image_72"]
|
||||
|
||||
self.slack_username = profile.dig("username").presence
|
||||
self.slack_username ||= profile.dig("display_name_normalized").presence
|
||||
self.slack_username ||= profile.dig("real_name_normalized").presence
|
||||
|
||||
self.username.blank? && self.username = self.slack_username
|
||||
self.slack_username = user_data["name"].presence
|
||||
self.slack_username ||= profile["display_name_normalized"].presence
|
||||
self.slack_username ||= profile["real_name_normalized"].presence
|
||||
end
|
||||
|
||||
def update_slack_status
|
||||
|
|
@ -359,7 +365,10 @@ class User < ApplicationRecord
|
|||
|
||||
return nil unless user_data["ok"]
|
||||
|
||||
email = user_data.dig("user", "profile", "email")&.downcase
|
||||
slack_user = user_data["user"] || {}
|
||||
profile = slack_user["profile"] || {}
|
||||
|
||||
email = profile["email"]&.downcase
|
||||
email_address = EmailAddress.find_or_initialize_by(email: email)
|
||||
email_address.source ||= :slack
|
||||
user = email_address.user
|
||||
|
|
@ -372,12 +381,12 @@ class User < ApplicationRecord
|
|||
end
|
||||
|
||||
user.slack_uid = data.dig("authed_user", "id")
|
||||
user.username ||= user_data.dig("user", "profile", "username")
|
||||
user.username ||= user_data.dig("user", "profile", "display_name_normalized")
|
||||
user.slack_username = user_data.dig("user", "profile", "username")
|
||||
user.slack_avatar_url = user_data.dig("user", "profile", "image_192") || user_data.dig("user", "profile", "image_72")
|
||||
user.slack_username = slack_user["name"].presence
|
||||
user.slack_username ||= profile["display_name_normalized"].presence
|
||||
user.slack_username ||= profile["real_name_normalized"].presence
|
||||
user.slack_avatar_url = profile["image_192"] || profile["image_72"]
|
||||
|
||||
user.parse_and_set_timezone(user_data.dig("user", "tz"))
|
||||
user.parse_and_set_timezone(slack_user["tz"])
|
||||
|
||||
user.slack_access_token = data["authed_user"]["access_token"]
|
||||
user.slack_scopes = data["authed_user"]["scope"]&.split(/,\s*/)
|
||||
|
|
@ -427,8 +436,7 @@ class User < ApplicationRecord
|
|||
|
||||
# Update GitHub-specific fields
|
||||
current_user.github_uid = github_uid
|
||||
current_user.username ||= user_data["login"]
|
||||
current_user.github_username = user_data["login"]
|
||||
current_user.github_username = user_data["login"].presence || user_data["name"].presence
|
||||
current_user.github_avatar_url = user_data["avatar_url"]
|
||||
current_user.github_access_token = data["access_token"]
|
||||
|
||||
|
|
@ -460,9 +468,8 @@ class User < ApplicationRecord
|
|||
end
|
||||
|
||||
def display_name
|
||||
return slack_username.presence.truncate(10) if slack_username.present?
|
||||
return github_username.presence.truncate(10) if github_username.present?
|
||||
return username.presence.truncate(10) if username.present?
|
||||
name = custom_name || slack_username || github_username
|
||||
return name if name.present?
|
||||
|
||||
# "zach@hackclub.com" -> "zach (email sign-up)"
|
||||
email = email_addresses&.first&.email
|
||||
|
|
@ -509,4 +516,27 @@ class User < ApplicationRecord
|
|||
def create_signup_activity
|
||||
create_activity :first_signup, owner: self
|
||||
end
|
||||
|
||||
def normalize_custom_name
|
||||
original = custom_name
|
||||
@custom_name_cleared_for_invisible = false
|
||||
|
||||
return if original.nil?
|
||||
|
||||
cleaned = original.gsub(/\p{Cf}/, "")
|
||||
stripped = cleaned.strip
|
||||
|
||||
if stripped.empty?
|
||||
self.custom_name = nil
|
||||
@custom_name_cleared_for_invisible = original.length.positive?
|
||||
else
|
||||
self.custom_name = stripped
|
||||
end
|
||||
end
|
||||
|
||||
def custom_name_must_be_visible
|
||||
if instance_variable_defined?(:@custom_name_cleared_for_invisible) && @custom_name_cleared_for_invisible
|
||||
errors.add(:custom_name, "must include visible characters")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@
|
|||
<div class="absolute top-0 p-3 rounded-lg shadow-lg <%= trust_level_bg %>"
|
||||
data-user-id="<%= user.id %>"
|
||||
style="left: <%= column_left + 2 %>px; width: <%= min_column_width_px - 4 %>px;"
|
||||
title="User ID: <%= user.id %> - <%= user.respond_to?(:username) && user.username.present? ? h(user.username) : h(user.email_addresses.first&.email) %> | Total Coded: <%= total_coded_time_seconds && total_coded_time_seconds > 0 ? short_time_detailed(total_coded_time_seconds) : '0m' %> | TZ: <%= h(user.timezone) %>">
|
||||
title="User ID: <%= user.id %> - <%= user.respond_to?(:display_name) && user.display_name.present? ? h(user.display_name) : h(user.email_addresses.first&.email) %> | Total Coded: <%= total_coded_time_seconds && total_coded_time_seconds > 0 ? short_time_detailed(total_coded_time_seconds) : '0m' %> | TZ: <%= h(user.timezone) %>">
|
||||
<div class="flex items-center space-x-1 mb-1">
|
||||
<%= render "shared/user_mention", user: user %>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
<div class="user-info flex items-center gap-2" title="<%= FlavorText.same_user.sample if user == current_user %>">
|
||||
<div class="user-info flex items-center gap-2" title="<%= if user == current_user
|
||||
FlavorText.same_user.sample
|
||||
else
|
||||
user.github_username.presence || user.slack_username.presence
|
||||
end %>">
|
||||
<%= image_tag user.avatar_url,
|
||||
size: "32x32",
|
||||
class: "rounded-full aspect-square border border-gray-300",
|
||||
alt: "#{h(user.username)}'s avatar" if user.avatar_url %>
|
||||
alt: "#{h(user.display_name)}'s avatar" if user.avatar_url %>
|
||||
<span class="inline-flex items-center gap-1">
|
||||
<% if local_assigns.fetch(:show, []).include?(:slack) && user.slack_uid.present? %>
|
||||
<%= link_to "@#{h(user.display_name)}", "https://hackclub.slack.com/team/#{user.slack_uid}", target: "_blank", class: "text-blue-500 hover:underline" %>
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
<% content_for :title do %>
|
||||
<%= @is_own_settings ? "My Settings" : "Settings | #{@user.username}" %>
|
||||
<%= @is_own_settings ? "My Settings" : "Settings | #{@user.display_name}" %>
|
||||
<% end %>
|
||||
|
||||
<div class="max-w-6xl mx-auto p-6 space-y-6">
|
||||
<header class="text-center mb-8">
|
||||
<h1 class="text-4xl font-bold text-white mb-2">
|
||||
<%= @is_own_settings ? "My Settings" : "Settings for #{@user.username}" %>
|
||||
<%= @is_own_settings ? "My Settings" : "Settings for #{@user.display_name}" %>
|
||||
</h1>
|
||||
<p class="text-muted text-lg">Change your Hackatime experience and preferences</p>
|
||||
</header>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div class="border border-primary rounded-xl p-6 bg-dark transition-all duration-200">
|
||||
<div class="border border-primary rounded-xl p-6 bg-dark transition-all duration-200 md:col-span-2">
|
||||
<div class="flex items-center gap-3 mb-4">
|
||||
<div class="p-2 bg-red-600/10 rounded">
|
||||
<span class="text-2xl">🚀</span>
|
||||
|
|
@ -68,6 +68,34 @@
|
|||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="border border-primary rounded-xl p-6 bg-dark transition-all duration-200">
|
||||
<div class="flex items-center gap-3 mb-4">
|
||||
<div class="p-2 bg-red-600/10 rounded">
|
||||
<span class="text-2xl">🪪</span>
|
||||
</div>
|
||||
<h2 class="text-xl font-semibold text-white" id="user_custom_name">Display Name</h2>
|
||||
</div>
|
||||
<%= form_with model: @user,
|
||||
url: @is_own_settings ? my_settings_path : settings_user_path(@user),
|
||||
method: :patch, local: false,
|
||||
class: "space-y-4" do |f| %>
|
||||
<div>
|
||||
<%= f.label :custom_name, "Custom display name", class: "block text-sm font-medium text-gray-200 mb-2" %>
|
||||
<%= f.text_field :custom_name,
|
||||
class: "w-full px-3 py-2 bg-gray-800 border border-gray-600 rounded text-white focus:border-primary focus:ring-1 focus:ring-primary",
|
||||
placeholder: "HackClubber",
|
||||
maxlength: User::CUSTOM_NAME_MAX_LENGTH %>
|
||||
<% if @user.errors[:custom_name].present? %>
|
||||
<p class="mt-1 text-xs text-red-400"><%= @user.errors[:custom_name].to_sentence %></p>
|
||||
<% end %>
|
||||
</div>
|
||||
<p class="text-xs text-gray-400">
|
||||
Choose a name to use in Hackatime. This will take priority over Slack or GitHub names when possible. Letters, numbers, "-" and "_" only, max <%= User::CUSTOM_NAME_MAX_LENGTH %> chars.
|
||||
</p>
|
||||
<%= f.submit "Save Settings", class: "w-full px-4 py-2 bg-primary text-white font-medium rounded transition-colors duration-200 cursor-pointer" %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="border border-primary rounded-xl p-6 bg-dark transition-all duration-200">
|
||||
<div class="flex items-center gap-3 mb-4">
|
||||
<div class="p-2 bg-red-600/10 rounded">
|
||||
|
|
|
|||
5
db/migrate/20251018181955_add_custom_name.rb
Normal file
5
db/migrate/20251018181955_add_custom_name.rb
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
class AddCustomName < ActiveRecord::Migration[8.0]
|
||||
def change
|
||||
add_column :users, :custom_name, :string
|
||||
end
|
||||
end
|
||||
5
db/migrate/20251021202329_deprecate_username.rb
Normal file
5
db/migrate/20251021202329_deprecate_username.rb
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
class DeprecateUsername < ActiveRecord::Migration[8.0]
|
||||
def change
|
||||
rename_column :users, :username, :deprecated_name
|
||||
end
|
||||
end
|
||||
5
db/schema.rb
generated
5
db/schema.rb
generated
|
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema[8.0].define(version: 2025_10_03_215127) do
|
||||
ActiveRecord::Schema[8.0].define(version: 2025_10_21_202329) do
|
||||
create_schema "pganalyze"
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
|
|
@ -543,7 +543,7 @@ ActiveRecord::Schema[8.0].define(version: 2025_10_03_215127) do
|
|||
t.string "slack_uid"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.string "username"
|
||||
t.string "deprecated_name"
|
||||
t.string "slack_avatar_url"
|
||||
t.boolean "uses_slack_status", default: false, null: false
|
||||
t.string "slack_scopes", default: [], array: true
|
||||
|
|
@ -562,6 +562,7 @@ ActiveRecord::Schema[8.0].define(version: 2025_10_03_215127) do
|
|||
t.boolean "allow_public_stats_lookup", default: true, null: false
|
||||
t.boolean "default_timezone_leaderboard", default: true, null: false
|
||||
t.integer "admin_level", default: 0, null: false
|
||||
t.string "custom_name"
|
||||
t.index ["github_uid", "github_access_token"], name: "index_users_on_github_uid_and_access_token"
|
||||
t.index ["github_uid"], name: "index_users_on_github_uid"
|
||||
t.index ["slack_uid"], name: "index_users_on_slack_uid", unique: true
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@ Doorkeeper::Application.find_or_create_by(
|
|||
if Rails.env.development?
|
||||
# Creating test user
|
||||
test_user = User.find_or_create_by(slack_uid: 'TEST123456') do |user|
|
||||
user.username = 'testuser'
|
||||
user.custom_name = 'testuser'
|
||||
user.slack_username = 'testuser'
|
||||
|
||||
# Before you had user.is_admin = true, does not work, changed it to that, looks like it works but idk how to use the admin pages so pls check this, i just guess coded this, the cmd to seed the db works without errors
|
||||
user.set_admin_level(:superadmin)
|
||||
|
|
@ -38,7 +39,7 @@ if Rails.env.development?
|
|||
end
|
||||
|
||||
puts "Created test user:"
|
||||
puts " Username: #{test_user.username}"
|
||||
puts " Username: #{test_user.display_name}"
|
||||
puts " Email: #{email.email}"
|
||||
puts " API Key: #{api_key.token}"
|
||||
puts " Sign-in Token: #{token.token}"
|
||||
|
|
|
|||
|
|
@ -246,8 +246,8 @@ class FlavorText
|
|||
r = []
|
||||
|
||||
r << "quit slacking off!" if user.slack_uid.present?
|
||||
r << "in the nick of time!" if %w[nick nicholas nickolas].include?(user.username)
|
||||
r << "just-in time!" if %w[justin justine].include?(user.username)
|
||||
r << "in the nick of time!" if %w[nick nicholas nickolas].include?(user.display_name)
|
||||
r << "just-in time!" if %w[justin justine].include?(user.display_name)
|
||||
|
||||
minutes_logged = Cache::MinutesLoggedJob.perform_now
|
||||
r << "in the past hour, #{minutes_logged} minutes have passed" if minutes_logged > 0
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ class TestWakatimeService
|
|||
def generate_summary
|
||||
summary = {}
|
||||
|
||||
summary[:username] = @user.username if @user.present?
|
||||
summary[:username] = @user.display_name if @user.present?
|
||||
summary[:user_id] = @user.id.to_s if @user.present?
|
||||
summary[:is_coding_activity_visible] = true if @user.present?
|
||||
summary[:is_other_usage_visible] = true if @user.present?
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ class WakatimeService
|
|||
def generate_summary
|
||||
summary = {}
|
||||
|
||||
summary[:username] = @user.username if @user.present?
|
||||
summary[:username] = @user.display_name if @user.present?
|
||||
summary[:user_id] = @user.id.to_s if @user.present?
|
||||
summary[:is_coding_activity_visible] = true if @user.present?
|
||||
summary[:is_other_usage_visible] = true if @user.present?
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue