diff --git a/app/controllers/auth/registrations_controller.rb b/app/controllers/auth/registrations_controller.rb index 417e2b63b..c095411c1 100644 --- a/app/controllers/auth/registrations_controller.rb +++ b/app/controllers/auth/registrations_controller.rb @@ -3,6 +3,7 @@ class Auth::RegistrationsController < Devise::RegistrationsController layout :determine_layout + before_action :set_invite, only: [:new, :create] before_action :check_enabled_registrations, only: [:new, :create] before_action :configure_sign_up_params, only: [:create] before_action :set_sessions, only: [:edit, :update] @@ -51,7 +52,7 @@ class Auth::RegistrationsController < Devise::RegistrationsController end def allowed_registrations? - Setting.open_registrations || (invite_code.present? && Invite.find_by(code: invite_code)&.valid_for_use?) + Setting.open_registrations || @invite&.valid_for_use? end def invite_code @@ -68,6 +69,10 @@ class Auth::RegistrationsController < Devise::RegistrationsController @instance_presenter = InstancePresenter.new end + def set_invite + @invite = invite_code.present? ? Invite.find_by(code: invite_code) : nil + end + def determine_layout %w(edit update).include?(action_name) ? 'admin' : 'auth' end diff --git a/app/controllers/invites_controller.rb b/app/controllers/invites_controller.rb index 26ef99b7e..5c30313f4 100644 --- a/app/controllers/invites_controller.rb +++ b/app/controllers/invites_controller.rb @@ -11,7 +11,7 @@ class InvitesController < ApplicationController authorize :invite, :create? @invites = invites - @invite = Invite.new(expires_in: 1.day.to_i) + @invite = Invite.new end def create @@ -42,6 +42,6 @@ class InvitesController < ApplicationController end def resource_params - params.require(:invite).permit(:max_uses, :expires_in) + params.require(:invite).permit(:max_uses, :expires_in, :autofollow) end end diff --git a/app/javascript/styles/mastodon/accounts.scss b/app/javascript/styles/mastodon/accounts.scss index 3ccce383b..14dc5dd62 100644 --- a/app/javascript/styles/mastodon/accounts.scss +++ b/app/javascript/styles/mastodon/accounts.scss @@ -458,23 +458,31 @@ } .account-card { - padding: 14px 10px; - background: $simple-background-color; border-radius: 4px; text-align: left; box-shadow: 0 0 15px rgba($base-shadow-color, 0.2); + background: $simple-background-color; - .detailed-status__display-name { + &__header { + background-size: cover; + background-position: center center; + height: 90px; + border-radius: 4px 4px 0 0; + } + + & > .detailed-status__display-name { display: block; overflow: hidden; - margin-bottom: 15px; + display: flex; + align-items: center; + padding: 10px; &:last-child { margin-bottom: 0; } - & > div { - float: left; + & > div:first-child { + flex: 0 0 auto; margin-right: 10px; width: 48px; height: 48px; @@ -483,9 +491,11 @@ .avatar { display: block; border-radius: 4px; + margin: 0; } .display-name { + flex: 1 0 auto; display: block; max-width: 100%; overflow: hidden; @@ -493,6 +503,10 @@ text-overflow: ellipsis; cursor: default; + & > .detailed-status__display-name { + margin-bottom: 0; + } + strong { font-weight: 500; color: $ui-base-color; @@ -519,9 +533,28 @@ } } - .account__header__content { - font-size: 14px; - color: $inverted-text-color; + .counter { + box-sizing: border-box; + flex: 0 0 auto; + color: $light-text-color; + padding: 0 10px; + cursor: default; + text-align: center; + position: relative; + line-height: 24px; + + .counter-label { + font-size: 12px; + display: block; + text-transform: uppercase; + } + + .counter-number { + font-weight: 500; + font-size: 16px; + color: $inverted-text-color; + font-family: 'mastodon-font-display', sans-serif; + } } } diff --git a/app/models/invite.rb b/app/models/invite.rb index 2250e588e..d0cc427c4 100644 --- a/app/models/invite.rb +++ b/app/models/invite.rb @@ -11,6 +11,7 @@ # uses :integer default(0), not null # created_at :datetime not null # updated_at :datetime not null +# autofollow :boolean default(FALSE), not null # class Invite < ApplicationRecord diff --git a/app/services/bootstrap_timeline_service.rb b/app/services/bootstrap_timeline_service.rb index c01e25824..db2c83e5d 100644 --- a/app/services/bootstrap_timeline_service.rb +++ b/app/services/bootstrap_timeline_service.rb @@ -2,13 +2,25 @@ class BootstrapTimelineService < BaseService def call(source_account) - bootstrap_timeline_accounts.each do |target_account| - FollowService.new.call(source_account, target_account) - end + @source_account = source_account + + autofollow_inviter! + autofollow_bootstrap_timeline_accounts! end private + def autofollow_inviter! + return unless @source_account&.user&.invite&.autofollow? + FollowService.new.call(@source_account, @source_account.user.invite.user.account) + end + + def autofollow_bootstrap_timeline_accounts! + bootstrap_timeline_accounts.each do |target_account| + FollowService.new.call(@source_account, target_account) + end + end + def bootstrap_timeline_accounts return @bootstrap_timeline_accounts if defined?(@bootstrap_timeline_accounts) diff --git a/app/views/auth/registrations/new.html.haml b/app/views/auth/registrations/new.html.haml index 2d4c0f5ac..0fac8e10d 100644 --- a/app/views/auth/registrations/new.html.haml +++ b/app/views/auth/registrations/new.html.haml @@ -7,6 +7,11 @@ = simple_form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| = render 'shared/error_messages', object: resource + - if @invite.present? && @invite.autofollow? + .fields-group{ style: 'margin-bottom: 30px' } + %p.hint{ style: 'text-align: center' }= t('invites.invited_by') + = render 'authorize_follows/card', account: @invite.user.account + = f.simple_fields_for :account do |ff| .input-with-append = ff.input :username, autofocus: true, placeholder: t('simple_form.labels.defaults.username'), required: true, input_html: { 'aria-label' => t('simple_form.labels.defaults.username'), :autocomplete => 'off' } diff --git a/app/views/authorize_follows/_card.html.haml b/app/views/authorize_follows/_card.html.haml index 9abcfd37e..edc03131f 100644 --- a/app/views/authorize_follows/_card.html.haml +++ b/app/views/authorize_follows/_card.html.haml @@ -1,4 +1,5 @@ .account-card + .account-card__header{ style: "background-image: url(#{account.header.url(:original)})" } .detailed-status__display-name %div = image_tag account.avatar.url(:original), alt: '', width: 48, height: 48, class: 'avatar' @@ -9,5 +10,14 @@ %strong.emojify= display_name(account, custom_emojify: true) %span @#{account.acct} - - if account.note? - .account__header__content.emojify= Formatter.instance.simplified_format(account) + .counter + %span.counter-number= number_to_human account.statuses_count, strip_insignificant_zeros: true + %span.counter-label= t('accounts.posts') + + .counter + %span.counter-number= number_to_human account.following_count, strip_insignificant_zeros: true + %span.counter-label= t('accounts.following') + + .counter + %span.counter-number= number_to_human account.followers_count, strip_insignificant_zeros: true + %span.counter-label= t('accounts.followers') diff --git a/app/views/invites/_form.html.haml b/app/views/invites/_form.html.haml index 3f0871f47..42a107bb2 100644 --- a/app/views/invites/_form.html.haml +++ b/app/views/invites/_form.html.haml @@ -5,5 +5,8 @@ = f.input :max_uses, wrapper: :with_label, collection: [1, 5, 10, 25, 50, 100], label_method: lambda { |num| I18n.t('invites.max_uses', count: num) }, prompt: I18n.t('invites.max_uses_prompt') = f.input :expires_in, wrapper: :with_label, collection: [30.minutes, 1.hour, 6.hours, 12.hours, 1.day, 1.week].map(&:to_i), label_method: lambda { |i| I18n.t("invites.expires_in.#{i}") }, prompt: I18n.t('invites.expires_in_prompt') + .fields-group + = f.input :autofollow, wrapper: :with_label + .actions = f.button :button, t('invites.generate'), type: :submit diff --git a/config/locales/en.yml b/config/locales/en.yml index d128f92f3..46875d2ec 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -514,6 +514,7 @@ en: '86400': 1 day expires_in_prompt: Never generate: Generate + invited_by: 'You were invited by:' max_uses: one: 1 use other: "%{count} uses" diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml index 85597e9a7..247a79218 100644 --- a/config/locales/simple_form.en.yml +++ b/config/locales/simple_form.en.yml @@ -3,6 +3,7 @@ en: simple_form: hints: defaults: + autofollow: People who sign up through the invite will automatically follow you avatar: PNG, GIF or JPG. At most 2MB. Will be downscaled to 400x400px bot: This account mainly performs automated actions and might not be monitored digest: Only sent after a long period of inactivity and only if you have received any personal messages in your absence @@ -30,6 +31,7 @@ en: name: Label value: Content defaults: + autofollow: Invite to follow your account avatar: Avatar bot: This is a bot account confirm_new_password: Confirm new password diff --git a/db/migrate/20180615122121_add_autofollow_to_invites.rb b/db/migrate/20180615122121_add_autofollow_to_invites.rb new file mode 100644 index 000000000..850b1d693 --- /dev/null +++ b/db/migrate/20180615122121_add_autofollow_to_invites.rb @@ -0,0 +1,17 @@ +require Rails.root.join('lib', 'mastodon', 'migration_helpers') + +class AddAutofollowToInvites < ActiveRecord::Migration[5.2] + include Mastodon::MigrationHelpers + + disable_ddl_transaction! + + def change + safety_assured do + add_column_with_default :invites, :autofollow, :bool, default: false, allow_null: false + end + end + + def down + remove_column :invites, :autofollow + end +end diff --git a/db/schema.rb b/db/schema.rb index 6564193a8..4c39de26a 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.define(version: 2018_06_09_104432) do +ActiveRecord::Schema.define(version: 2018_06_15_122121) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -219,6 +219,7 @@ ActiveRecord::Schema.define(version: 2018_06_09_104432) do t.integer "uses", default: 0, null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.boolean "autofollow", default: false, null: false t.index ["code"], name: "index_invites_on_code", unique: true t.index ["user_id"], name: "index_invites_on_user_id" end