Merge remote-tracking branch 'origin/master' into merge-upstream
Conflicts: .env.production.sample app/controllers/auth/confirmations_controller.rb db/schema.rblolsob-rspec
commit
4f8122a98c
|
@ -138,3 +138,52 @@ STREAMING_CLUSTER_NUM=1
|
||||||
|
|
||||||
# Maximum allowed character count
|
# Maximum allowed character count
|
||||||
# MAX_TOOT_CHARS=500
|
# MAX_TOOT_CHARS=500
|
||||||
|
|
||||||
|
# PAM authentication (optional)
|
||||||
|
# PAM_ENABLED=true
|
||||||
|
# Suffix for email address generation (nil by default)
|
||||||
|
# PAM_DEFAULT_SUFFIX=pam
|
||||||
|
# Name of the pam service (pam "auth" section is evaluated)
|
||||||
|
# PAM_DEFAULT_SERVICE=rpam
|
||||||
|
# Name of the pam service used for checking if an user can register (pam "account" section is evaluated)
|
||||||
|
# PAM_CONTROLLED_SERVICE=rpam
|
||||||
|
|
||||||
|
# Optional CAS authentication (cf. omniauth-cas) :
|
||||||
|
# CAS_ENABLED=true
|
||||||
|
# CAS_URL=https://sso.myserver.com/
|
||||||
|
# CAS_HOST=sso.myserver.com/
|
||||||
|
# CAS_PORT=443
|
||||||
|
# CAS_SSL=true
|
||||||
|
# CAS_VALIDATE_URL=
|
||||||
|
# CAS_CALLBACK_URL=
|
||||||
|
# CAS_LOGOUT_URL=
|
||||||
|
# CAS_LOGIN_URL=
|
||||||
|
# CAS_UID_FIELD='user'
|
||||||
|
# CAS_CA_PATH=
|
||||||
|
# CAS_DISABLE_SSL_VERIFICATION=false
|
||||||
|
# CAS_UID_KEY='user'
|
||||||
|
# CAS_NAME_KEY='name'
|
||||||
|
# CAS_EMAIL_KEY='email'
|
||||||
|
# CAS_NICKNAME_KEY='nickname'
|
||||||
|
# CAS_FIRST_NAME_KEY='firstname'
|
||||||
|
# CAS_LAST_NAME_KEY='lastname'
|
||||||
|
# CAS_LOCATION_KEY='location'
|
||||||
|
# CAS_IMAGE_KEY='image'
|
||||||
|
# CAS_PHONE_KEY='phone'
|
||||||
|
|
||||||
|
# Optional SAML authentication (cf. omniauth-saml)
|
||||||
|
# SAML_ENABLED=true
|
||||||
|
# SAML_ACS_URL=
|
||||||
|
# SAML_ISSUER=http://localhost:3000/auth/auth/saml/metadata
|
||||||
|
# SAML_IDP_SSO_TARGET_URL=https://idp.testshib.org/idp/profile/SAML2/Redirect/SSO
|
||||||
|
# SAML_IDP_CERT=
|
||||||
|
# SAML_IDP_CERT_FINGERPRINT=
|
||||||
|
# SAML_NAME_IDENTIFIER_FORMAT=
|
||||||
|
# SAML_CERT=
|
||||||
|
# SAML_PRIVATE_KEY=
|
||||||
|
# SAML_SECURITY_WANT_ASSERTION_SIGNED=true
|
||||||
|
# SAML_SECURITY_WANT_ASSERTION_ENCRYPTED=true
|
||||||
|
# SAML_ATTRIBUTES_STATEMENTS_UID="urn:oid:0.9.2342.19200300.100.1.1"
|
||||||
|
# SAML_ATTRIBUTES_STATEMENTS_EMAIL="urn:oid:1.3.6.1.4.1.5923.1.1.1.6"
|
||||||
|
# SAML_ATTRIBUTES_STATEMENTS_FULL_NAME="urn:oid:2.5.4.42"
|
||||||
|
# SAML_UID_ATTRIBUTE="urn:oid:0.9.2342.19200300.100.1.1"
|
||||||
|
|
5
Gemfile
5
Gemfile
|
@ -32,7 +32,10 @@ gem 'cld3', '~> 3.2.0'
|
||||||
gem 'devise', '~> 4.4'
|
gem 'devise', '~> 4.4'
|
||||||
gem 'devise-two-factor', '~> 3.0'
|
gem 'devise-two-factor', '~> 3.0'
|
||||||
|
|
||||||
gem 'devise_pam_authenticatable2', '~> 8.0'
|
gem 'devise_pam_authenticatable2', '~> 8.0', install_if: -> { ENV['PAM_ENABLED'] == 'true' }
|
||||||
|
gem 'omniauth-cas', '~> 1.1', install_if: -> { ENV['CAS_ENABLED'] == 'true' }
|
||||||
|
gem 'omniauth-saml', '~> 1.8', install_if: -> { ENV['SAML_ENABLED'] == 'true' }
|
||||||
|
gem 'omniauth', '~> 1.2'
|
||||||
|
|
||||||
gem 'doorkeeper', '~> 4.2'
|
gem 'doorkeeper', '~> 4.2'
|
||||||
gem 'fast_blank', '~> 1.0'
|
gem 'fast_blank', '~> 1.0'
|
||||||
|
|
16
Gemfile.lock
16
Gemfile.lock
|
@ -201,6 +201,7 @@ GEM
|
||||||
hamster (3.0.0)
|
hamster (3.0.0)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
hashdiff (0.3.7)
|
hashdiff (0.3.7)
|
||||||
|
hashie (3.5.7)
|
||||||
highline (1.7.10)
|
highline (1.7.10)
|
||||||
hiredis (0.6.1)
|
hiredis (0.6.1)
|
||||||
hkdf (0.3.0)
|
hkdf (0.3.0)
|
||||||
|
@ -304,6 +305,16 @@ GEM
|
||||||
sidekiq (>= 3.5.0)
|
sidekiq (>= 3.5.0)
|
||||||
statsd-ruby (~> 1.2.0)
|
statsd-ruby (~> 1.2.0)
|
||||||
oj (3.3.10)
|
oj (3.3.10)
|
||||||
|
omniauth (1.8.1)
|
||||||
|
hashie (>= 3.4.6, < 3.6.0)
|
||||||
|
rack (>= 1.6.2, < 3)
|
||||||
|
omniauth-cas (1.1.1)
|
||||||
|
addressable (~> 2.3)
|
||||||
|
nokogiri (~> 1.5)
|
||||||
|
omniauth (~> 1.2)
|
||||||
|
omniauth-saml (1.9.0)
|
||||||
|
omniauth (~> 1.3, >= 1.3.2)
|
||||||
|
ruby-saml (~> 1.4, >= 1.4.3)
|
||||||
orm_adapter (0.5.0)
|
orm_adapter (0.5.0)
|
||||||
ostatus2 (2.0.3)
|
ostatus2 (2.0.3)
|
||||||
addressable (~> 2.5)
|
addressable (~> 2.5)
|
||||||
|
@ -456,6 +467,8 @@ GEM
|
||||||
unicode-display_width (~> 1.0, >= 1.0.1)
|
unicode-display_width (~> 1.0, >= 1.0.1)
|
||||||
ruby-oembed (0.12.0)
|
ruby-oembed (0.12.0)
|
||||||
ruby-progressbar (1.9.0)
|
ruby-progressbar (1.9.0)
|
||||||
|
ruby-saml (1.6.1)
|
||||||
|
nokogiri (>= 1.5.10)
|
||||||
rufus-scheduler (3.4.2)
|
rufus-scheduler (3.4.2)
|
||||||
et-orbi (~> 1.0)
|
et-orbi (~> 1.0)
|
||||||
safe_yaml (1.0.4)
|
safe_yaml (1.0.4)
|
||||||
|
@ -607,6 +620,9 @@ DEPENDENCIES
|
||||||
nokogiri (~> 1.8)
|
nokogiri (~> 1.8)
|
||||||
nsa (~> 0.2)
|
nsa (~> 0.2)
|
||||||
oj (~> 3.3)
|
oj (~> 3.3)
|
||||||
|
omniauth (~> 1.2)
|
||||||
|
omniauth-cas (~> 1.1)
|
||||||
|
omniauth-saml (~> 1.8)
|
||||||
ostatus2 (~> 2.0)
|
ostatus2 (~> 2.0)
|
||||||
ox (~> 2.8)
|
ox (~> 2.8)
|
||||||
paperclip (~> 5.1)
|
paperclip (~> 5.1)
|
||||||
|
|
|
@ -39,6 +39,7 @@ sudo apt-get install \
|
||||||
libidn11-dev \
|
libidn11-dev \
|
||||||
libprotobuf-dev \
|
libprotobuf-dev \
|
||||||
libreadline-dev \
|
libreadline-dev \
|
||||||
|
libpam0g-dev \
|
||||||
-y
|
-y
|
||||||
|
|
||||||
# Install rvm
|
# Install rvm
|
||||||
|
|
|
@ -36,7 +36,7 @@ class AboutController < ApplicationController
|
||||||
|
|
||||||
def initial_state_params
|
def initial_state_params
|
||||||
{
|
{
|
||||||
settings: {},
|
settings: { known_fediverse: Setting.show_known_fediverse_at_about_page },
|
||||||
token: current_session&.token,
|
token: current_session&.token,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
|
@ -19,6 +19,7 @@ module Admin
|
||||||
min_invite_role
|
min_invite_role
|
||||||
activity_api_enabled
|
activity_api_enabled
|
||||||
peers_api_enabled
|
peers_api_enabled
|
||||||
|
show_known_fediverse_at_about_page
|
||||||
).freeze
|
).freeze
|
||||||
|
|
||||||
BOOLEAN_SETTINGS = %w(
|
BOOLEAN_SETTINGS = %w(
|
||||||
|
@ -28,6 +29,7 @@ module Admin
|
||||||
show_staff_badge
|
show_staff_badge
|
||||||
activity_api_enabled
|
activity_api_enabled
|
||||||
peers_api_enabled
|
peers_api_enabled
|
||||||
|
show_known_fediverse_at_about_page
|
||||||
).freeze
|
).freeze
|
||||||
|
|
||||||
UPLOAD_SETTINGS = %w(
|
UPLOAD_SETTINGS = %w(
|
||||||
|
|
|
@ -10,7 +10,7 @@ class Api::V1::Accounts::RelationshipsController < Api::BaseController
|
||||||
accounts = Account.where(id: account_ids).select('id')
|
accounts = Account.where(id: account_ids).select('id')
|
||||||
# .where doesn't guarantee that our results are in the same order
|
# .where doesn't guarantee that our results are in the same order
|
||||||
# we requested them, so return the "right" order to the requestor.
|
# we requested them, so return the "right" order to the requestor.
|
||||||
@accounts = accounts.index_by(&:id).values_at(*account_ids)
|
@accounts = accounts.index_by(&:id).values_at(*account_ids).compact
|
||||||
render json: @accounts, each_serializer: REST::RelationshipSerializer, relationships: relationships
|
render json: @accounts, each_serializer: REST::RelationshipSerializer, relationships: relationships
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
class Auth::ConfirmationsController < Devise::ConfirmationsController
|
class Auth::ConfirmationsController < Devise::ConfirmationsController
|
||||||
layout 'auth'
|
layout 'auth'
|
||||||
|
|
||||||
|
before_action :set_user, only: [:finish_signup]
|
||||||
before_action :set_pack
|
before_action :set_pack
|
||||||
|
|
||||||
private
|
private
|
||||||
|
@ -10,4 +11,26 @@ class Auth::ConfirmationsController < Devise::ConfirmationsController
|
||||||
def set_pack
|
def set_pack
|
||||||
use_pack 'auth'
|
use_pack 'auth'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# GET/PATCH /users/:id/finish_signup
|
||||||
|
def finish_signup
|
||||||
|
return unless request.patch? && params[:user]
|
||||||
|
if @user.update(user_params)
|
||||||
|
@user.skip_reconfirmation!
|
||||||
|
sign_in(@user, bypass: true)
|
||||||
|
redirect_to root_path, notice: I18n.t('devise.confirmations.send_instructions')
|
||||||
|
else
|
||||||
|
@show_errors = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_user
|
||||||
|
@user = current_user
|
||||||
|
end
|
||||||
|
|
||||||
|
def user_params
|
||||||
|
params.require(:user).permit(:email)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Auth::OmniauthCallbacksController < Devise::OmniauthCallbacksController
|
||||||
|
skip_before_action :verify_authenticity_token
|
||||||
|
|
||||||
|
def self.provides_callback_for(provider)
|
||||||
|
provider_id = provider.to_s.chomp '_oauth2'
|
||||||
|
|
||||||
|
define_method provider do
|
||||||
|
@user = User.find_for_oauth(request.env['omniauth.auth'], current_user)
|
||||||
|
|
||||||
|
if @user.persisted?
|
||||||
|
sign_in_and_redirect @user, event: :authentication
|
||||||
|
set_flash_message(:notice, :success, kind: provider_id.capitalize) if is_navigational_format?
|
||||||
|
else
|
||||||
|
session["devise.#{provider}_data"] = request.env['omniauth.auth']
|
||||||
|
redirect_to new_user_registration_url
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Devise.omniauth_configs.each_key do |provider|
|
||||||
|
provides_callback_for provider
|
||||||
|
end
|
||||||
|
|
||||||
|
def after_sign_in_path_for(resource)
|
||||||
|
if resource.email_verified?
|
||||||
|
root_path
|
||||||
|
else
|
||||||
|
finish_signup_path
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -6,6 +6,7 @@ import { hydrateStore } from '../actions/store';
|
||||||
import { IntlProvider, addLocaleData } from 'react-intl';
|
import { IntlProvider, addLocaleData } from 'react-intl';
|
||||||
import { getLocale } from '../locales';
|
import { getLocale } from '../locales';
|
||||||
import PublicTimeline from '../features/standalone/public_timeline';
|
import PublicTimeline from '../features/standalone/public_timeline';
|
||||||
|
import CommunityTimeline from '../features/standalone/community_timeline';
|
||||||
import HashtagTimeline from '../features/standalone/hashtag_timeline';
|
import HashtagTimeline from '../features/standalone/hashtag_timeline';
|
||||||
import initialState from '../initial_state';
|
import initialState from '../initial_state';
|
||||||
|
|
||||||
|
@ -23,17 +24,24 @@ export default class TimelineContainer extends React.PureComponent {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
locale: PropTypes.string.isRequired,
|
locale: PropTypes.string.isRequired,
|
||||||
hashtag: PropTypes.string,
|
hashtag: PropTypes.string,
|
||||||
|
showPublicTimeline: PropTypes.bool.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
showPublicTimeline: initialState.settings.known_fediverse,
|
||||||
};
|
};
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { locale, hashtag } = this.props;
|
const { locale, hashtag, showPublicTimeline } = this.props;
|
||||||
|
|
||||||
let timeline;
|
let timeline;
|
||||||
|
|
||||||
if (hashtag) {
|
if (hashtag) {
|
||||||
timeline = <HashtagTimeline hashtag={hashtag} />;
|
timeline = <HashtagTimeline hashtag={hashtag} />;
|
||||||
} else {
|
} else if (showPublicTimeline) {
|
||||||
timeline = <PublicTimeline />;
|
timeline = <PublicTimeline />;
|
||||||
|
} else {
|
||||||
|
timeline = <CommunityTimeline />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import StatusListContainer from '../../ui/containers/status_list_container';
|
||||||
|
import {
|
||||||
|
refreshCommunityTimeline,
|
||||||
|
expandCommunityTimeline,
|
||||||
|
} from '../../../actions/timelines';
|
||||||
|
import Column from '../../../components/column';
|
||||||
|
import ColumnHeader from '../../../components/column_header';
|
||||||
|
import { defineMessages, injectIntl } from 'react-intl';
|
||||||
|
import { connectCommunityStream } from '../../../actions/streaming';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
title: { id: 'standalone.public_title', defaultMessage: 'A look inside...' },
|
||||||
|
});
|
||||||
|
|
||||||
|
@connect()
|
||||||
|
@injectIntl
|
||||||
|
export default class CommunityTimeline extends React.PureComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
dispatch: PropTypes.func.isRequired,
|
||||||
|
intl: PropTypes.object.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
handleHeaderClick = () => {
|
||||||
|
this.column.scrollTop();
|
||||||
|
}
|
||||||
|
|
||||||
|
setRef = c => {
|
||||||
|
this.column = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount () {
|
||||||
|
const { dispatch } = this.props;
|
||||||
|
|
||||||
|
dispatch(refreshCommunityTimeline());
|
||||||
|
this.disconnect = dispatch(connectCommunityStream());
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount () {
|
||||||
|
if (this.disconnect) {
|
||||||
|
this.disconnect();
|
||||||
|
this.disconnect = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleLoadMore = () => {
|
||||||
|
this.props.dispatch(expandCommunityTimeline());
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { intl } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Column ref={this.setRef}>
|
||||||
|
<ColumnHeader
|
||||||
|
icon='users'
|
||||||
|
title={intl.formatMessage(messages.title)}
|
||||||
|
onClick={this.handleHeaderClick}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<StatusListContainer
|
||||||
|
timelineId='community'
|
||||||
|
loadMore={this.handleLoadMore}
|
||||||
|
scrollKey='standalone_public_timeline'
|
||||||
|
trackScroll={false}
|
||||||
|
/>
|
||||||
|
</Column>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1230,6 +1230,15 @@
|
||||||
],
|
],
|
||||||
"path": "app/javascript/mastodon/features/public_timeline/index.json"
|
"path": "app/javascript/mastodon/features/public_timeline/index.json"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"descriptors": [
|
||||||
|
{
|
||||||
|
"defaultMessage": "A look inside...",
|
||||||
|
"id": "standalone.public_title"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"path": "app/javascript/mastodon/features/standalone/community_timeline/index.json"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"descriptors": [
|
"descriptors": [
|
||||||
{
|
{
|
||||||
|
|
|
@ -568,3 +568,21 @@ code {
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.alternative-login {
|
||||||
|
margin-top: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
font-size: 16px;
|
||||||
|
color: $ui-base-lighter-color;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
border: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ class NotificationMailer < ApplicationMailer
|
||||||
@me = recipient
|
@me = recipient
|
||||||
@status = notification.target_status
|
@status = notification.target_status
|
||||||
|
|
||||||
return if @me.user.disabled?
|
return if @me.user.disabled? || @status.nil?
|
||||||
|
|
||||||
locale_for_account(@me) do
|
locale_for_account(@me) do
|
||||||
thread_by_conversation(@status.conversation)
|
thread_by_conversation(@status.conversation)
|
||||||
|
@ -33,7 +33,7 @@ class NotificationMailer < ApplicationMailer
|
||||||
@account = notification.from_account
|
@account = notification.from_account
|
||||||
@status = notification.target_status
|
@status = notification.target_status
|
||||||
|
|
||||||
return if @me.user.disabled?
|
return if @me.user.disabled? || @status.nil?
|
||||||
|
|
||||||
locale_for_account(@me) do
|
locale_for_account(@me) do
|
||||||
thread_by_conversation(@status.conversation)
|
thread_by_conversation(@status.conversation)
|
||||||
|
@ -46,7 +46,7 @@ class NotificationMailer < ApplicationMailer
|
||||||
@account = notification.from_account
|
@account = notification.from_account
|
||||||
@status = notification.target_status
|
@status = notification.target_status
|
||||||
|
|
||||||
return if @me.user.disabled?
|
return if @me.user.disabled? || @status.nil?
|
||||||
|
|
||||||
locale_for_account(@me) do
|
locale_for_account(@me) do
|
||||||
thread_by_conversation(@status.conversation)
|
thread_by_conversation(@status.conversation)
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Omniauthable
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
TEMP_EMAIL_PREFIX = 'change@me'
|
||||||
|
TEMP_EMAIL_REGEX = /\Achange@me/
|
||||||
|
|
||||||
|
included do
|
||||||
|
def omniauth_providers
|
||||||
|
Devise.omniauth_configs.keys
|
||||||
|
end
|
||||||
|
|
||||||
|
def email_verified?
|
||||||
|
email && email !~ TEMP_EMAIL_REGEX
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class_methods do
|
||||||
|
def find_for_oauth(auth, signed_in_resource = nil)
|
||||||
|
# EOLE-SSO Patch
|
||||||
|
auth.uid = (auth.uid[0][:uid] || auth.uid[0][:user]) if auth.uid.is_a? Hashie::Array
|
||||||
|
identity = Identity.find_for_oauth(auth)
|
||||||
|
|
||||||
|
# If a signed_in_resource is provided it always overrides the existing user
|
||||||
|
# to prevent the identity being locked with accidentally created accounts.
|
||||||
|
# Note that this may leave zombie accounts (with no associated identity) which
|
||||||
|
# can be cleaned up at a later date.
|
||||||
|
user = signed_in_resource ? signed_in_resource : identity.user
|
||||||
|
user = create_for_oauth(auth) if user.nil?
|
||||||
|
|
||||||
|
if identity.user.nil?
|
||||||
|
identity.user = user
|
||||||
|
identity.save!
|
||||||
|
end
|
||||||
|
|
||||||
|
user
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_for_oauth(auth)
|
||||||
|
# Check if the user exists with provided email if the provider gives us a
|
||||||
|
# verified email. If no verified email was provided or the user already
|
||||||
|
# exists, we assign a temporary email and ask the user to verify it on
|
||||||
|
# the next step via Auth::ConfirmationsController.finish_signup
|
||||||
|
|
||||||
|
user = User.new(user_params_from_auth(auth))
|
||||||
|
user.account.avatar_remote_url = auth.info.image if auth.info.image =~ /\A#{URI.regexp(%w(http https))}\z/
|
||||||
|
user.skip_confirmation!
|
||||||
|
user.save!
|
||||||
|
user
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def user_params_from_auth(auth)
|
||||||
|
email_is_verified = auth.info.email && (auth.info.verified || auth.info.verified_email)
|
||||||
|
email = auth.info.email if email_is_verified && !User.exists?(email: auth.info.email)
|
||||||
|
|
||||||
|
{
|
||||||
|
email: email ? email : "#{TEMP_EMAIL_PREFIX}-#{auth.uid}-#{auth.provider}.com",
|
||||||
|
password: Devise.friendly_token[0, 20],
|
||||||
|
account_attributes: {
|
||||||
|
username: ensure_unique_username(auth.uid),
|
||||||
|
display_name: [auth.info.first_name, auth.info.last_name].join(' '),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def ensure_unique_username(starting_username)
|
||||||
|
username = starting_username
|
||||||
|
i = 0
|
||||||
|
|
||||||
|
while Account.exists?(username: username)
|
||||||
|
i += 1
|
||||||
|
username = "#{starting_username}_#{i}"
|
||||||
|
end
|
||||||
|
|
||||||
|
username
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -34,6 +34,8 @@ class Form::AdminSettings
|
||||||
:activity_api_enabled=,
|
:activity_api_enabled=,
|
||||||
:peers_api_enabled,
|
:peers_api_enabled,
|
||||||
:peers_api_enabled=,
|
:peers_api_enabled=,
|
||||||
|
:show_known_fediverse_at_about_page,
|
||||||
|
:show_known_fediverse_at_about_page=,
|
||||||
to: Setting
|
to: Setting
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
# == Schema Information
|
||||||
|
#
|
||||||
|
# Table name: identities
|
||||||
|
#
|
||||||
|
# id :integer not null, primary key
|
||||||
|
# user_id :integer
|
||||||
|
# provider :string default(""), not null
|
||||||
|
# uid :string default(""), not null
|
||||||
|
# created_at :datetime not null
|
||||||
|
# updated_at :datetime not null
|
||||||
|
#
|
||||||
|
|
||||||
|
class Identity < ApplicationRecord
|
||||||
|
belongs_to :user, dependent: :destroy
|
||||||
|
validates :uid, presence: true, uniqueness: { scope: :provider }
|
||||||
|
validates :provider, presence: true
|
||||||
|
|
||||||
|
def self.find_for_oauth(auth)
|
||||||
|
find_or_create_by(uid: auth.uid, provider: auth.provider)
|
||||||
|
end
|
||||||
|
end
|
|
@ -39,6 +39,7 @@
|
||||||
|
|
||||||
class User < ApplicationRecord
|
class User < ApplicationRecord
|
||||||
include Settings::Extend
|
include Settings::Extend
|
||||||
|
include Omniauthable
|
||||||
|
|
||||||
ACTIVE_DURATION = 14.days
|
ACTIVE_DURATION = 14.days
|
||||||
|
|
||||||
|
@ -51,7 +52,8 @@ class User < ApplicationRecord
|
||||||
devise :registerable, :recoverable, :rememberable, :trackable, :validatable,
|
devise :registerable, :recoverable, :rememberable, :trackable, :validatable,
|
||||||
:confirmable
|
:confirmable
|
||||||
|
|
||||||
devise :pam_authenticatable
|
devise :pam_authenticatable if Devise.pam_authentication
|
||||||
|
devise :omniauthable
|
||||||
|
|
||||||
belongs_to :account, inverse_of: :user
|
belongs_to :account, inverse_of: :user
|
||||||
belongs_to :invite, counter_cache: :uses, optional: true
|
belongs_to :invite, counter_cache: :uses, optional: true
|
||||||
|
|
|
@ -23,6 +23,8 @@ class StatusLengthValidator < ActiveModel::Validator
|
||||||
end
|
end
|
||||||
|
|
||||||
def countable_text(status)
|
def countable_text(status)
|
||||||
|
return '' if status.text.nil?
|
||||||
|
|
||||||
status.text.dup.tap do |new_text|
|
status.text.dup.tap do |new_text|
|
||||||
new_text.gsub!(FetchLinkCardService::URL_PATTERN, 'x' * 23)
|
new_text.gsub!(FetchLinkCardService::URL_PATTERN, 'x' * 23)
|
||||||
new_text.gsub!(Account::MENTION_RE, '@\2')
|
new_text.gsub!(Account::MENTION_RE, '@\2')
|
||||||
|
|
|
@ -18,6 +18,9 @@
|
||||||
.fields-group
|
.fields-group
|
||||||
= f.input :timeline_preview, as: :boolean, wrapper: :with_label, label: t('admin.settings.timeline_preview.title'), hint: t('admin.settings.timeline_preview.desc_html')
|
= f.input :timeline_preview, as: :boolean, wrapper: :with_label, label: t('admin.settings.timeline_preview.title'), hint: t('admin.settings.timeline_preview.desc_html')
|
||||||
|
|
||||||
|
.fields-group
|
||||||
|
= f.input :show_known_fediverse_at_about_page, as: :boolean, wrapper: :with_label, label: t('admin.settings.show_known_fediverse_at_about_page.title'), hint: t('admin.settings.show_known_fediverse_at_about_page.desc_html')
|
||||||
|
|
||||||
.fields-group
|
.fields-group
|
||||||
= f.input :show_staff_badge, as: :boolean, wrapper: :with_label, label: t('admin.settings.show_staff_badge.title'), hint: t('admin.settings.show_staff_badge.desc_html')
|
= f.input :show_staff_badge, as: :boolean, wrapper: :with_label, label: t('admin.settings.show_staff_badge.title'), hint: t('admin.settings.show_staff_badge.desc_html')
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
- content_for :page_title do
|
||||||
|
= t('auth.confirm_email')
|
||||||
|
|
||||||
|
= simple_form_for(current_user, as: 'user', url: finish_signup_path, html: { role: 'form'}) do |f|
|
||||||
|
- if @show_errors && current_user.errors.any?
|
||||||
|
#error_explanation
|
||||||
|
- current_user.errors.full_messages.each do |msg|
|
||||||
|
= msg
|
||||||
|
%br
|
||||||
|
|
||||||
|
= f.input :email
|
||||||
|
|
||||||
|
.actions
|
||||||
|
= f.submit t('auth.confirm_email'), class: 'button'
|
|
@ -14,4 +14,13 @@
|
||||||
.actions
|
.actions
|
||||||
= f.button :button, t('auth.login'), type: :submit
|
= f.button :button, t('auth.login'), type: :submit
|
||||||
|
|
||||||
|
- if devise_mapping.omniauthable? and resource_class.omniauth_providers.any?
|
||||||
|
.simple_form.alternative-login
|
||||||
|
%h4= t('auth.or_log_in_with')
|
||||||
|
|
||||||
|
.actions
|
||||||
|
- resource_class.omniauth_providers.each do |provider|
|
||||||
|
= link_to omniauth_authorize_path(resource_name, provider), class: "button button-#{provider}" do
|
||||||
|
= t("auth.providers.#{provider}", default: provider.to_s.chomp("_oauth2").capitalize)
|
||||||
|
|
||||||
.form-footer= render 'auth/shared/links'
|
.form-footer= render 'auth/shared/links'
|
||||||
|
|
|
@ -46,6 +46,7 @@ ignore_missing:
|
||||||
- 'terms.body_html'
|
- 'terms.body_html'
|
||||||
- 'application_mailer.salutation'
|
- 'application_mailer.salutation'
|
||||||
- 'errors.500'
|
- 'errors.500'
|
||||||
|
- 'auth.providers.*'
|
||||||
|
|
||||||
ignore_unused:
|
ignore_unused:
|
||||||
- 'activemodel.errors.*'
|
- 'activemodel.errors.*'
|
||||||
|
|
|
@ -315,22 +315,13 @@ Devise.setup do |config|
|
||||||
# so you need to do it manually. For the users scope, it would be:
|
# so you need to do it manually. For the users scope, it would be:
|
||||||
# config.omniauth_path_prefix = '/my_engine/users/auth'
|
# config.omniauth_path_prefix = '/my_engine/users/auth'
|
||||||
|
|
||||||
# PAM: only look for email field
|
if ENV['PAM_ENABLED'] == 'true'
|
||||||
config.usernamefield = nil
|
config.pam_authentication = true
|
||||||
config.emailfield = "email"
|
config.usernamefield = nil
|
||||||
|
config.emailfield = 'email'
|
||||||
# authentication with pam possible
|
config.check_at_sign = true
|
||||||
# if not enabled, all pam settings are ignored
|
config.pam_default_suffix = ENV.fetch('PAM_DEFAULT_SUFFIX') { nil }
|
||||||
#config.pam_authentication = true
|
config.pam_default_service = ENV.fetch('PAM_DEFAULT_SERVICE') { 'rpam' }
|
||||||
# check if email is actually a username
|
config.pam_controlled_service = ENV.fetch('PAM_CONTROLLED_SERVICE') { 'rpam' }
|
||||||
config.check_at_sign = true
|
end
|
||||||
# suffix for email address generation (warning: without pam must provide email in the pam environment)
|
|
||||||
config.pam_default_suffix = "pam"
|
|
||||||
# name of the pam service
|
|
||||||
# pam "auth" section is evaluated
|
|
||||||
config.pam_default_service = "rpam"
|
|
||||||
# name of the pam service used for checking if an user can register
|
|
||||||
# pam "account" section is evaluated
|
|
||||||
# nil for allowing registration of pam names (not recommended)
|
|
||||||
config.pam_controlled_service = "rpam"
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
Rails.application.config.middleware.use OmniAuth::Builder do
|
||||||
|
# Vanilla omniauth stategies
|
||||||
|
end
|
||||||
|
|
||||||
|
Devise.setup do |config|
|
||||||
|
# Devise omniauth strategies
|
||||||
|
|
||||||
|
# CAS strategy
|
||||||
|
if ENV['CAS_ENABLED'] == 'true'
|
||||||
|
cas_options = {}
|
||||||
|
cas_options[:url] = ENV['CAS_URL'] if ENV['CAS_URL']
|
||||||
|
cas_options[:host] = ENV['CAS_HOST'] if ENV['CAS_HOST']
|
||||||
|
cas_options[:port] = ENV['CAS_PORT'] if ENV['CAS_PORT']
|
||||||
|
cas_options[:ssl] = ENV['CAS_SSL'] == 'true' if ENV['CAS_SSL']
|
||||||
|
cas_options[:validate_url] = ENV['CAS_VALIDATE_URL'] if ENV['CAS_VALIDATE_URL']
|
||||||
|
cas_options[:callback_url] = ENV['CAS_CALLBACK_URL'] if ENV['CAS_CALLBACK_URL']
|
||||||
|
cas_options[:logout_url] = ENV['CAS_LOGOUT_URL'] if ENV['CAS_LOGOUT_URL']
|
||||||
|
cas_options[:login_url] = ENV['CAS_LOGIN_URL'] if ENV['CAS_LOGIN_URL']
|
||||||
|
cas_options[:uid_field] = ENV['CAS_UID_FIELD'] || 'user' if ENV['CAS_UID_FIELD']
|
||||||
|
cas_options[:ca_path] = ENV['CAS_CA_PATH'] if ENV['CAS_CA_PATH']
|
||||||
|
cas_options[:disable_ssl_verification] = ENV['CAS_DISABLE_SSL_VERIFICATION'] == 'true' if ENV['CAS_DISABLE_SSL_VERIFICATION']
|
||||||
|
cas_options[:uid_key] = ENV['CAS_UID_KEY'] || 'user'
|
||||||
|
cas_options[:name_key] = ENV['CAS_NAME_KEY'] || 'name'
|
||||||
|
cas_options[:email_key] = ENV['CAS_EMAIL_KEY'] || 'email'
|
||||||
|
cas_options[:nickname_key] = ENV['CAS_NICKNAME_KEY'] || 'nickname'
|
||||||
|
cas_options[:first_name_key] = ENV['CAS_FIRST_NAME_KEY'] || 'firstname'
|
||||||
|
cas_options[:last_name_key] = ENV['CAS_LAST_NAME_KEY'] || 'lastname'
|
||||||
|
cas_options[:location_key] = ENV['CAS_LOCATION_KEY'] || 'location'
|
||||||
|
cas_options[:image_key] = ENV['CAS_IMAGE_KEY'] || 'image'
|
||||||
|
cas_options[:phone_key] = ENV['CAS_PHONE_KEY'] || 'phone'
|
||||||
|
config.omniauth :cas, cas_options
|
||||||
|
end
|
||||||
|
|
||||||
|
# SAML strategy
|
||||||
|
if ENV['SAML_ENABLED'] == 'true'
|
||||||
|
saml_options = {}
|
||||||
|
saml_options[:assertion_consumer_service_url] = ENV['SAML_ACS_URL'] if ENV['SAML_ACS_URL']
|
||||||
|
saml_options[:issuer] = ENV['SAML_ISSUER'] if ENV['SAML_ISSUER']
|
||||||
|
saml_options[:idp_sso_target_url] = ENV['SAML_IDP_SSO_TARGET_URL'] if ENV['SAML_IDP_SSO_TARGET_URL']
|
||||||
|
saml_options[:idp_sso_target_url_runtime_params] = ENV['SAML_IDP_SSO_TARGET_PARAMS'] if ENV['SAML_IDP_SSO_TARGET_PARAMS'] # FIXME: Should be parsable Hash
|
||||||
|
saml_options[:idp_cert] = ENV['SAML_IDP_CERT'] if ENV['SAML_IDP_CERT']
|
||||||
|
saml_options[:idp_cert_fingerprint] = ENV['SAML_IDP_CERT_FINGERPRINT'] if ENV['SAML_IDP_CERT_FINGERPRINT']
|
||||||
|
saml_options[:idp_cert_fingerprint_validator] = ENV['SAML_IDP_CERT_FINGERPRINT_VALIDATOR'] if ENV['SAML_IDP_CERT_FINGERPRINT_VALIDATOR'] # FIXME: Should be Lambda { |fingerprint| }
|
||||||
|
saml_options[:name_identifier_format] = ENV['SAML_NAME_IDENTIFIER_FORMAT'] if ENV['SAML_NAME_IDENTIFIER_FORMAT']
|
||||||
|
saml_options[:request_attributes] = {}
|
||||||
|
saml_options[:certificate] = ENV['SAML_CERT'] if ENV['SAML_CERT']
|
||||||
|
saml_options[:private_key] = ENV['SAML_PRIVATE_KEY'] if ENV['SAML_PRIVATE_KEY']
|
||||||
|
saml_options[:security] = {}
|
||||||
|
saml_options[:security][:want_assertions_signed] = ENV['SAML_SECURITY_WANT_ASSERTION_SIGNED'] == 'true'
|
||||||
|
saml_options[:security][:want_assertions_encrypted] = ENV['SAML_SECURITY_WANT_ASSERTION_ENCRYPTED'] == 'true'
|
||||||
|
saml_options[:attribute_statements] = {}
|
||||||
|
saml_options[:attribute_statements][:uid] = [ENV['SAML_ATTRIBUTES_STATEMENTS_UID']] if ENV['SAML_ATTRIBUTES_STATEMENTS_UID']
|
||||||
|
saml_options[:attribute_statements][:email] = [ENV['SAML_ATTRIBUTES_STATEMENTS_EMAIL']] if ENV['SAML_ATTRIBUTES_STATEMENTS_EMAIL']
|
||||||
|
saml_options[:attribute_statements][:full_name] = [ENV['SAML_ATTRIBUTES_STATEMENTS_FULL_NAME']] if ENV['SAML_ATTRIBUTES_STATEMENTS_FULL_NAME']
|
||||||
|
saml_options[:uid_attribute] = ENV['SAML_UID_ATTRIBUTE'] if ENV['SAML_UID_ATTRIBUTE']
|
||||||
|
config.omniauth :saml, saml_options
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -290,6 +290,9 @@ en:
|
||||||
open:
|
open:
|
||||||
desc_html: Allow anyone to create an account
|
desc_html: Allow anyone to create an account
|
||||||
title: Open registration
|
title: Open registration
|
||||||
|
show_known_fediverse_at_about_page:
|
||||||
|
desc_html: When toggled, it will show toots from all the known fediverse on preview. Otherwise it will only show local toots.
|
||||||
|
title: Show known fediverse on timeline preview
|
||||||
show_staff_badge:
|
show_staff_badge:
|
||||||
desc_html: Show a staff badge on a user page
|
desc_html: Show a staff badge on a user page
|
||||||
title: Show staff badge
|
title: Show staff badge
|
||||||
|
@ -355,6 +358,7 @@ en:
|
||||||
auth:
|
auth:
|
||||||
agreement_html: By signing up you agree to follow <a href="%{rules_path}">the rules of the instance</a> and <a href="%{terms_path}">our terms of service</a>.
|
agreement_html: By signing up you agree to follow <a href="%{rules_path}">the rules of the instance</a> and <a href="%{terms_path}">our terms of service</a>.
|
||||||
change_password: Security
|
change_password: Security
|
||||||
|
confirm_email: Confirm email
|
||||||
delete_account: Delete account
|
delete_account: Delete account
|
||||||
delete_account_html: If you wish to delete your account, you can <a href="%{path}">proceed here</a>. You will be asked for confirmation.
|
delete_account_html: If you wish to delete your account, you can <a href="%{path}">proceed here</a>. You will be asked for confirmation.
|
||||||
didnt_get_confirmation: Didn't receive confirmation instructions?
|
didnt_get_confirmation: Didn't receive confirmation instructions?
|
||||||
|
@ -364,6 +368,10 @@ en:
|
||||||
logout: Logout
|
logout: Logout
|
||||||
migrate_account: Move to a different account
|
migrate_account: Move to a different account
|
||||||
migrate_account_html: If you wish to redirect this account to a different one, you can <a href="%{path}">configure it here</a>.
|
migrate_account_html: If you wish to redirect this account to a different one, you can <a href="%{path}">configure it here</a>.
|
||||||
|
or_log_in_with: Or log in with
|
||||||
|
providers:
|
||||||
|
cas: CAS
|
||||||
|
saml: SAML
|
||||||
register: Sign up
|
register: Sign up
|
||||||
resend_confirmation: Resend confirmation instructions
|
resend_confirmation: Resend confirmation instructions
|
||||||
reset_password: Reset password
|
reset_password: Reset password
|
||||||
|
|
|
@ -355,6 +355,7 @@ fr:
|
||||||
auth:
|
auth:
|
||||||
agreement_html: En vous inscrivant, vous souscrivez <a href="%{rules_path}">aux règles de l’instance</a> et à <a href="%{terms_path}">nos conditions d’utilisation</a>.
|
agreement_html: En vous inscrivant, vous souscrivez <a href="%{rules_path}">aux règles de l’instance</a> et à <a href="%{terms_path}">nos conditions d’utilisation</a>.
|
||||||
change_password: Sécurité
|
change_password: Sécurité
|
||||||
|
confirm_email: Confirmer mon adresse mail
|
||||||
delete_account: Supprimer le compte
|
delete_account: Supprimer le compte
|
||||||
delete_account_html: Si vous désirez supprimer votre compte, vous pouvez <a href="%{path}">cliquer ici</a>. Il vous sera demandé de confirmer cette action.
|
delete_account_html: Si vous désirez supprimer votre compte, vous pouvez <a href="%{path}">cliquer ici</a>. Il vous sera demandé de confirmer cette action.
|
||||||
didnt_get_confirmation: Vous n’avez pas reçu les consignes de confirmation ?
|
didnt_get_confirmation: Vous n’avez pas reçu les consignes de confirmation ?
|
||||||
|
@ -364,6 +365,7 @@ fr:
|
||||||
logout: Se déconnecter
|
logout: Se déconnecter
|
||||||
migrate_account: Déplacer vers un compte différent
|
migrate_account: Déplacer vers un compte différent
|
||||||
migrate_account_html: Si vous voulez rediriger ce compte vers un autre, vous pouvez le <a href="%{path}">configurer ici</a>.
|
migrate_account_html: Si vous voulez rediriger ce compte vers un autre, vous pouvez le <a href="%{path}">configurer ici</a>.
|
||||||
|
or_log_in_with: Ou authentifiez-vous avec
|
||||||
register: S’inscrire
|
register: S’inscrire
|
||||||
resend_confirmation: Envoyer à nouveau les consignes de confirmation
|
resend_confirmation: Envoyer à nouveau les consignes de confirmation
|
||||||
reset_password: Réinitialiser le mot de passe
|
reset_password: Réinitialiser le mot de passe
|
||||||
|
|
|
@ -291,6 +291,9 @@ pl:
|
||||||
open:
|
open:
|
||||||
desc_html: Pozwól każdemu na założenie konta
|
desc_html: Pozwól każdemu na założenie konta
|
||||||
title: Otwarta rejestracja
|
title: Otwarta rejestracja
|
||||||
|
show_known_fediverse_at_about_page:
|
||||||
|
desc_html: Jeśli włączone, podgląd instancji będzie wyświetlał wpisy z całego Fediwersum. W innym przypadku, będą wyświetlane tylko lokalne wpisy.
|
||||||
|
title: Pokazuj wszystkie znane wpisy na podglądzie instancji
|
||||||
show_staff_badge:
|
show_staff_badge:
|
||||||
desc_html: Pokazuj odznakę uprawnień na stronie profilu użytkownika
|
desc_html: Pokazuj odznakę uprawnień na stronie profilu użytkownika
|
||||||
title: Pokazuj odznakę administracji
|
title: Pokazuj odznakę administracji
|
||||||
|
|
|
@ -290,6 +290,9 @@ pt-BR:
|
||||||
open:
|
open:
|
||||||
desc_html: Permitir que qualquer um crie uma conta
|
desc_html: Permitir que qualquer um crie uma conta
|
||||||
title: Cadastro aberto
|
title: Cadastro aberto
|
||||||
|
show_known_fediverse_at_about_page:
|
||||||
|
desc_html: Quando ligado, vai mostrar toots de todo o fediverso conhecido na prévia da timeline. Senão, mostra somente toots locais.
|
||||||
|
title: Mostrar fediverso conhecido na prévia da timeline
|
||||||
show_staff_badge:
|
show_staff_badge:
|
||||||
desc_html: Mostrar uma insígnia de Equipe na página de usuário
|
desc_html: Mostrar uma insígnia de Equipe na página de usuário
|
||||||
title: Mostrar insígnia de equipe
|
title: Mostrar insígnia de equipe
|
||||||
|
|
|
@ -24,9 +24,11 @@ Rails.application.routes.draw do
|
||||||
|
|
||||||
devise_scope :user do
|
devise_scope :user do
|
||||||
get '/invite/:invite_code', to: 'auth/registrations#new', as: :public_invite
|
get '/invite/:invite_code', to: 'auth/registrations#new', as: :public_invite
|
||||||
|
match '/auth/finish_signup' => 'auth/confirmations#finish_signup', via: [:get, :patch], as: :finish_signup
|
||||||
end
|
end
|
||||||
|
|
||||||
devise_for :users, path: 'auth', controllers: {
|
devise_for :users, path: 'auth', controllers: {
|
||||||
|
omniauth_callbacks: 'auth/omniauth_callbacks',
|
||||||
sessions: 'auth/sessions',
|
sessions: 'auth/sessions',
|
||||||
registrations: 'auth/registrations',
|
registrations: 'auth/registrations',
|
||||||
passwords: 'auth/passwords',
|
passwords: 'auth/passwords',
|
||||||
|
|
|
@ -51,6 +51,7 @@ defaults: &defaults
|
||||||
bootstrap_timeline_accounts: ''
|
bootstrap_timeline_accounts: ''
|
||||||
activity_api_enabled: true
|
activity_api_enabled: true
|
||||||
peers_api_enabled: true
|
peers_api_enabled: true
|
||||||
|
show_known_fediverse_at_about_page: true
|
||||||
development:
|
development:
|
||||||
<<: *defaults
|
<<: *defaults
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
class CreateIdentities < ActiveRecord::Migration[5.0]
|
||||||
|
def change
|
||||||
|
create_table :identities do |t|
|
||||||
|
t.references :user, foreign_key: { on_delete: :cascade }
|
||||||
|
t.string :provider, null: false, default: ''
|
||||||
|
t.string :uid, null: false, default: ''
|
||||||
|
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
15
db/schema.rb
15
db/schema.rb
|
@ -10,7 +10,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 20180109143959) do
|
ActiveRecord::Schema.define(version: 20180204034416) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
|
@ -182,6 +182,15 @@ ActiveRecord::Schema.define(version: 20180109143959) do
|
||||||
t.index ["account_id"], name: "index_glitch_keyword_mutes_on_account_id"
|
t.index ["account_id"], name: "index_glitch_keyword_mutes_on_account_id"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
create_table "identities", id: :serial, force: :cascade do |t|
|
||||||
|
t.integer "user_id"
|
||||||
|
t.string "provider", default: "", null: false
|
||||||
|
t.string "uid", default: "", null: false
|
||||||
|
t.datetime "created_at", null: false
|
||||||
|
t.datetime "updated_at", null: false
|
||||||
|
t.index ["user_id"], name: "index_identities_on_user_id"
|
||||||
|
end
|
||||||
|
|
||||||
create_table "imports", force: :cascade do |t|
|
create_table "imports", force: :cascade do |t|
|
||||||
t.integer "type", null: false
|
t.integer "type", null: false
|
||||||
t.boolean "approved", default: false, null: false
|
t.boolean "approved", default: false, null: false
|
||||||
|
@ -536,7 +545,11 @@ ActiveRecord::Schema.define(version: 20180109143959) do
|
||||||
add_foreign_key "follow_requests", "accounts", name: "fk_76d644b0e7", on_delete: :cascade
|
add_foreign_key "follow_requests", "accounts", name: "fk_76d644b0e7", on_delete: :cascade
|
||||||
add_foreign_key "follows", "accounts", column: "target_account_id", name: "fk_745ca29eac", on_delete: :cascade
|
add_foreign_key "follows", "accounts", column: "target_account_id", name: "fk_745ca29eac", on_delete: :cascade
|
||||||
add_foreign_key "follows", "accounts", name: "fk_32ed1b5560", on_delete: :cascade
|
add_foreign_key "follows", "accounts", name: "fk_32ed1b5560", on_delete: :cascade
|
||||||
|
<<<<<<< HEAD
|
||||||
add_foreign_key "glitch_keyword_mutes", "accounts", on_delete: :cascade
|
add_foreign_key "glitch_keyword_mutes", "accounts", on_delete: :cascade
|
||||||
|
=======
|
||||||
|
add_foreign_key "identities", "users", on_delete: :cascade
|
||||||
|
>>>>>>> origin/master
|
||||||
add_foreign_key "imports", "accounts", name: "fk_6db1b6e408", on_delete: :cascade
|
add_foreign_key "imports", "accounts", name: "fk_6db1b6e408", on_delete: :cascade
|
||||||
add_foreign_key "invites", "users", on_delete: :cascade
|
add_foreign_key "invites", "users", on_delete: :cascade
|
||||||
add_foreign_key "list_accounts", "accounts", on_delete: :cascade
|
add_foreign_key "list_accounts", "accounts", on_delete: :cascade
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
Fabricator(:identity) do
|
||||||
|
user nil
|
||||||
|
provider "MyString"
|
||||||
|
uid "MyString"
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe Identity, type: :model do
|
||||||
|
pending "add some examples to (or delete) #{__FILE__}"
|
||||||
|
end
|
Loading…
Reference in New Issue