diff --git a/app/assets/images/social_link_icons/bluesky.svg b/app/assets/images/social_link_icons/bluesky.svg new file mode 100644 index 0000000000..0cbe91f4de --- /dev/null +++ b/app/assets/images/social_link_icons/bluesky.svg @@ -0,0 +1,4 @@ + \ No newline at end of file diff --git a/app/assets/images/social_link_icons/discord.svg b/app/assets/images/social_link_icons/discord.svg new file mode 100644 index 0000000000..5f5bdd6aa6 --- /dev/null +++ b/app/assets/images/social_link_icons/discord.svg @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/app/assets/images/social_link_icons/facebook.svg b/app/assets/images/social_link_icons/facebook.svg new file mode 100644 index 0000000000..e9e7963544 --- /dev/null +++ b/app/assets/images/social_link_icons/facebook.svg @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/app/assets/images/social_link_icons/github.svg b/app/assets/images/social_link_icons/github.svg new file mode 100644 index 0000000000..51b1a80019 --- /dev/null +++ b/app/assets/images/social_link_icons/github.svg @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/app/assets/images/social_link_icons/gitlab.svg b/app/assets/images/social_link_icons/gitlab.svg new file mode 100644 index 0000000000..760ea7c6ca --- /dev/null +++ b/app/assets/images/social_link_icons/gitlab.svg @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/app/assets/images/social_link_icons/instagram.svg b/app/assets/images/social_link_icons/instagram.svg new file mode 100644 index 0000000000..2724fbd5bd --- /dev/null +++ b/app/assets/images/social_link_icons/instagram.svg @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/app/assets/images/social_link_icons/line.svg b/app/assets/images/social_link_icons/line.svg new file mode 100644 index 0000000000..3808c88e23 --- /dev/null +++ b/app/assets/images/social_link_icons/line.svg @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/app/assets/images/social_link_icons/linkedin.svg b/app/assets/images/social_link_icons/linkedin.svg new file mode 100644 index 0000000000..59f2e4533f --- /dev/null +++ b/app/assets/images/social_link_icons/linkedin.svg @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/app/assets/images/social_link_icons/mastodon.svg b/app/assets/images/social_link_icons/mastodon.svg new file mode 100644 index 0000000000..44a2730f37 --- /dev/null +++ b/app/assets/images/social_link_icons/mastodon.svg @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/app/assets/images/social_link_icons/medium.svg b/app/assets/images/social_link_icons/medium.svg new file mode 100644 index 0000000000..b0c359ec84 --- /dev/null +++ b/app/assets/images/social_link_icons/medium.svg @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/app/assets/images/social_link_icons/other.svg b/app/assets/images/social_link_icons/other.svg new file mode 100644 index 0000000000..b78b4c73d9 --- /dev/null +++ b/app/assets/images/social_link_icons/other.svg @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/app/assets/images/social_link_icons/quora.svg b/app/assets/images/social_link_icons/quora.svg new file mode 100644 index 0000000000..e18e02e3f0 --- /dev/null +++ b/app/assets/images/social_link_icons/quora.svg @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/app/assets/images/social_link_icons/reddit.svg b/app/assets/images/social_link_icons/reddit.svg new file mode 100644 index 0000000000..dba2cb3f4b --- /dev/null +++ b/app/assets/images/social_link_icons/reddit.svg @@ -0,0 +1,4 @@ + \ No newline at end of file diff --git a/app/assets/images/social_link_icons/skype.svg b/app/assets/images/social_link_icons/skype.svg new file mode 100644 index 0000000000..ff4833d9da --- /dev/null +++ b/app/assets/images/social_link_icons/skype.svg @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/app/assets/images/social_link_icons/slack.svg b/app/assets/images/social_link_icons/slack.svg new file mode 100644 index 0000000000..4698314471 --- /dev/null +++ b/app/assets/images/social_link_icons/slack.svg @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/app/assets/images/social_link_icons/snapchat.svg b/app/assets/images/social_link_icons/snapchat.svg new file mode 100644 index 0000000000..a19a51993d --- /dev/null +++ b/app/assets/images/social_link_icons/snapchat.svg @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/app/assets/images/social_link_icons/stackoverflow.svg b/app/assets/images/social_link_icons/stackoverflow.svg new file mode 100644 index 0000000000..24aaca0ace --- /dev/null +++ b/app/assets/images/social_link_icons/stackoverflow.svg @@ -0,0 +1,4 @@ + \ No newline at end of file diff --git a/app/assets/images/social_link_icons/strava.svg b/app/assets/images/social_link_icons/strava.svg new file mode 100644 index 0000000000..8e8625c167 --- /dev/null +++ b/app/assets/images/social_link_icons/strava.svg @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/app/assets/images/social_link_icons/substack.svg b/app/assets/images/social_link_icons/substack.svg new file mode 100644 index 0000000000..d0d6d6d3aa --- /dev/null +++ b/app/assets/images/social_link_icons/substack.svg @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/app/assets/images/social_link_icons/telegram.svg b/app/assets/images/social_link_icons/telegram.svg new file mode 100644 index 0000000000..1b77dce2ad --- /dev/null +++ b/app/assets/images/social_link_icons/telegram.svg @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/app/assets/images/social_link_icons/threads.svg b/app/assets/images/social_link_icons/threads.svg new file mode 100644 index 0000000000..99ec962892 --- /dev/null +++ b/app/assets/images/social_link_icons/threads.svg @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/app/assets/images/social_link_icons/tiktok.svg b/app/assets/images/social_link_icons/tiktok.svg new file mode 100644 index 0000000000..18f99ae1e9 --- /dev/null +++ b/app/assets/images/social_link_icons/tiktok.svg @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/app/assets/images/social_link_icons/twitch.svg b/app/assets/images/social_link_icons/twitch.svg new file mode 100644 index 0000000000..8e3ac6fbf2 --- /dev/null +++ b/app/assets/images/social_link_icons/twitch.svg @@ -0,0 +1,4 @@ + \ No newline at end of file diff --git a/app/assets/images/social_link_icons/twitter_x.svg b/app/assets/images/social_link_icons/twitter_x.svg new file mode 100644 index 0000000000..d51006674d --- /dev/null +++ b/app/assets/images/social_link_icons/twitter_x.svg @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/app/assets/images/social_link_icons/vimeo.svg b/app/assets/images/social_link_icons/vimeo.svg new file mode 100644 index 0000000000..13c9fcf58b --- /dev/null +++ b/app/assets/images/social_link_icons/vimeo.svg @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/app/assets/images/social_link_icons/whatsapp.svg b/app/assets/images/social_link_icons/whatsapp.svg new file mode 100644 index 0000000000..e24000ea43 --- /dev/null +++ b/app/assets/images/social_link_icons/whatsapp.svg @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/app/assets/images/social_link_icons/youtube.svg b/app/assets/images/social_link_icons/youtube.svg new file mode 100644 index 0000000000..38b2704b08 --- /dev/null +++ b/app/assets/images/social_link_icons/youtube.svg @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/app/assets/javascripts/user.js b/app/assets/javascripts/user.js index 2af9e18cbd..b82c1c79b3 100644 --- a/app/assets/javascripts/user.js +++ b/app/assets/javascripts/user.js @@ -10,6 +10,35 @@ $(document).ready(function () { const defaultHomeZoom = 12; let map, marker, deleted_lat, deleted_lon; + if ($("#social_links").length) { + $("#add-social-link").click(function (event) { + event.preventDefault(); + const newIndex = -Date.now(); + const socialLinkForm = $(` +
+ `); + + socialLinkForm.find("button").click(function () { + $(this).parent().remove(); + }); + + $("#social_links").append(socialLinkForm); + }); + + $(".social_link_destroy input[type='checkbox']").change(function () { + $(this).parent().parent().addClass("d-none"); + }); + + $(".social_link_destroy input[type='checkbox']:checked").each(function () { + $(this).parent().parent().addClass("d-none"); + }); + } + if ($("#map").length) { map = L.map("map", { attributionControl: false, diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb index 4005176ce1..428b1e36f6 100644 --- a/app/controllers/profiles_controller.rb +++ b/app/controllers/profiles_controller.rb @@ -12,6 +12,9 @@ class ProfilesController < ApplicationController def edit; end def update + social_links_params = params.require(:user).permit(:social_links_attributes => [:id, :url, :_destroy]) + current_user.assign_attributes(social_links_params) + if params[:user][:description] != current_user.description current_user.description = params[:user][:description] current_user.description_format = "markdown" diff --git a/app/models/social_link.rb b/app/models/social_link.rb new file mode 100644 index 0000000000..37d300bf41 --- /dev/null +++ b/app/models/social_link.rb @@ -0,0 +1,68 @@ +# == Schema Information +# +# Table name: social_links +# +# id :bigint(8) not null, primary key +# user_id :bigint(8) not null +# url :string not null +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_social_links_on_user_id (user_id) +# +# Foreign Keys +# +# fk_rails_... (user_id => users.id) +# + +class SocialLink < ApplicationRecord + belongs_to :user + + validates :url, :format => { :with => %r{\Ahttps?://.+\z}, :message => :http_parse_error } + + URL_PATTERNS = { + :bluesky => %r{\Ahttps?://(?:www\.)?bsky\.app/profile/([a-zA-Z0-9\._-]+)}, + :discord => %r{\Ahttps?://(?:www\.)?discord\.com/users/(\d+)}, + :facebook => %r{\Ahttps?://(?:www\.)?facebook\.com/([a-zA-Z0-9.]+)}, + :github => %r{\Ahttps?://(?:www\.)?github\.com/([a-zA-Z0-9_-]+)}, + :gitlab => %r{\Ahttps?://(?:www\.)?gitlab\.com/([a-zA-Z0-9_-]+)}, + :instagram => %r{\Ahttps?://(?:www\.)?instagram\.com/([a-zA-Z0-9._]+)}, + :linkedin => %r{\Ahttps?://(?:www\.)?linkedin\.com/in/([a-zA-Z0-9_-]+)}, + :line => %r{\Ahttps?://(?:www\.)?line\.me/ti/p/([a-zA-Z0-9_-]+)}, + :mastodon => %r{\Ahttps?://(?:(?:www\.)?mastodon\.social|en\.osm\.town)/@([a-zA-Z0-9_]+)}, + :medium => %r{\Ahttps?://(?:www\.)?medium\.com/@([a-zA-Z0-9_]+)}, + :quora => %r{\Ahttps?://(?:www\.)?quora\.com/profile/([a-zA-Z0-9_-]+)}, + :reddit => %r{\Ahttps?://(?:www\.)?reddit\.com/user/([a-zA-Z0-9_-]+)}, + :skype => %r{\Ahttps?://join\.skype\.com/invite/([a-zA-Z0-9_-]+)}, + :slack => %r{\Ahttps?://join\.slack\.com/shareDM/([a-zA-Z0-9_~-]+)}, + :snapchat => %r{\Ahttps?://(?:www\.)?snapchat\.com/add/([a-zA-Z0-9_-]+)}, + :stackoverflow => %r{\Ahttps?://(?:www\.)?stackoverflow\.com/users/\d+/([a-zA-Z0-9_-]+)}, + :strava => %r{\Ahttps?://(?:www\.)?strava\.com/athletes/([a-zA-Z0-9_-]+)}, + :substack => %r{\Ahttps?://(?:www\.)?substack\.com/@([a-zA-Z0-9_-]+)}, + :telegram => %r{\Ahttps?://(?:www\.)?t\.me/([a-zA-Z0-9_]+)}, + :threads => %r{\Ahttps?://(?:www\.)?threads\.net/@([a-zA-Z0-9_]+)}, + :tiktok => %r{\Ahttps?://(?:www\.)?tiktok\.com/@([a-zA-Z0-9_]+)}, + :twitch => %r{\Ahttps?://(?:www\.)?twitch\.tv/([a-zA-Z0-9_]+)}, + :twitter_x => %r{\Ahttps?://(?:www\.)?(?:twitter|x)\.com/([a-zA-Z0-9_]+)}, + :vimeo => %r{\Ahttps?://(?:www\.)?vimeo\.com/([a-zA-Z0-9_]+)}, + :whatsapp => %r{\Ahttps?://wa\.me/(\d+)}, + :youtube => %r{\Ahttps?://(?:www\.)?youtube\.com/@([a-zA-Z0-9_-]+)} + }.freeze + + NO_USERNAME_PLATFORMS = %w[discord line skype slack].freeze + + def parsed + URL_PATTERNS.each do |platform, pattern| + names = url.match(pattern) + if names + return { + :platform => platform.to_s, + :name => NO_USERNAME_PLATFORMS.include?(platform.to_s) ? platform.to_s.capitalize : names[1] + } + end + end + { :platform => nil, :name => url.gsub(%r{https?://}, "") } + end +end diff --git a/app/models/user.rb b/app/models/user.rb index 8d061e26bb..38f09b8cf9 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -87,6 +87,9 @@ class User < ApplicationRecord has_many :reports + has_many :social_links + accepts_nested_attributes_for :social_links, :allow_destroy => true + scope :visible, -> { where(:status => %w[pending active confirmed]) } scope :active, -> { where(:status => %w[active confirmed]) } scope :identifiable, -> { where(:data_public => true) } diff --git a/app/views/profiles/edit.html.erb b/app/views/profiles/edit.html.erb index ac76b4d2d5..1e32015c93 100644 --- a/app/views/profiles/edit.html.erb +++ b/app/views/profiles/edit.html.erb @@ -9,6 +9,22 @@ <%= bootstrap_form_for current_user, :url => { :action => :update }, :html => { :multipart => true, :autocomplete => :off } do |f| %> <%= f.richtext_field :description, :cols => 80, :rows => 20 %> + +