This commit is contained in:
Baptiste Lemoine 2019-12-02 16:33:04 +01:00
parent d806ddd7ab
commit 08755fbae2
14 changed files with 2085 additions and 334 deletions

1
.browserslistrc Normal file
View File

@ -0,0 +1 @@
defaults

7
.gitignore vendored
View File

@ -58,3 +58,10 @@ yarn-debug.log
# Ignore Docker option files
docker-compose.override.yml
/public/packs
/public/packs-test
/node_modules
/yarn-error.log
yarn-debug.log*
.yarn-integrity

View File

@ -1 +1 @@
2.6.0
2.6.4

View File

@ -50,7 +50,7 @@
class Account < ApplicationRecord
USERNAME_RE = /[a-z0-9_]+([a-z0-9_\.-]+[a-z0-9_]+)?/i
MENTION_RE = /(?<=^|[^\/[:word:]])@((#{USERNAME_RE})(?:@[a-z0-9\.\-]+[a-z0-9]+)?)/i
MENTION_RE = /(?<=^|[^\/[:word:]])@((#{USERNAME_RE})(?:@[a-z0-9\.\-]+[a-z0-9]+)?)/i
include AccountAssociations
include AccountAvatar
@ -63,8 +63,8 @@ class Account < ApplicationRecord
include DomainNormalizable
TRUST_LEVELS = {
untrusted: 0,
trusted: 1,
untrusted: 0,
trusted: 1,
}.freeze
enum protocol: [:ostatus, :activitypub]
@ -72,16 +72,16 @@ class Account < ApplicationRecord
validates :username, presence: true
# Remote user validations
validates :username, uniqueness: { scope: :domain, case_sensitive: true }, if: -> { !local? && will_save_change_to_username? }
validates :username, format: { with: /\A#{USERNAME_RE}\z/i }, if: -> { !local? && will_save_change_to_username? }
validates :username, uniqueness: {scope: :domain, case_sensitive: true}, if: -> { !local? && will_save_change_to_username? }
validates :username, format: {with: /\A#{USERNAME_RE}\z/i}, if: -> { !local? && will_save_change_to_username? }
# Local user validations
validates :username, format: { with: /\A[a-z0-9_]+\z/i }, length: { maximum: 30 }, if: -> { local? && will_save_change_to_username? && actor_type != 'Application' }
validates :username, format: {with: /\A[a-z0-9_]+\z/i}, length: {maximum: 30}, if: -> { local? && will_save_change_to_username? && actor_type != 'Application' }
validates_with UniqueUsernameValidator, if: -> { local? && will_save_change_to_username? }
validates_with UnreservedUsernameValidator, if: -> { local? && will_save_change_to_username? }
validates :display_name, length: { maximum: 30 }, if: -> { local? && will_save_change_to_display_name? }
validates :note, note_length: { maximum: 500 }, if: -> { local? && will_save_change_to_note? }
validates :fields, length: { maximum: 4 }, if: -> { local? && will_save_change_to_fields? }
validates :display_name, length: {maximum: 30}, if: -> { local? && will_save_change_to_display_name? }
validates :note, note_length: {maximum: 500}, if: -> { local? && will_save_change_to_note? }
validates :fields, length: {maximum: 4}, if: -> { local? && will_save_change_to_fields? }
scope :remote, -> { where.not(domain: nil) }
scope :local, -> { where(domain: nil) }
@ -100,7 +100,7 @@ class Account < ApplicationRecord
scope :matches_domain, ->(value) { where(arel_table[:domain].matches("%#{value}%")) }
scope :searchable, -> { without_suspended.where(moved_to_account_id: nil) }
scope :discoverable, -> { searchable.without_silenced.where(discoverable: true).left_outer_joins(:account_stat) }
scope :tagged_with, ->(tag) { joins(:accounts_tags).where(accounts_tags: { tag_id: tag }) }
scope :tagged_with, ->(tag) { joins(:accounts_tags).where(accounts_tags: {tag_id: tag}) }
scope :by_recent_status, -> { order(Arel.sql('(case when account_stats.last_status_at is null then 1 else 0 end) asc, account_stats.last_status_at desc, accounts.id desc')) }
scope :popular, -> { order('account_stats.followers_count desc') }
scope :by_domain_and_subdomains, ->(domain) { where(domain: domain).or(where(arel_table[:domain].matches('%.' + domain))) }
@ -267,7 +267,7 @@ class Account < ApplicationRecord
end
def fields_attributes=(attributes)
fields = []
fields = []
old_fields = self[:fields] || []
old_fields = [] if old_fields.is_a?(Hash)
@ -297,7 +297,7 @@ class Account < ApplicationRecord
tmp = [] if tmp.is_a?(Hash)
(DEFAULT_FIELDS_SIZE - tmp.size).times do
tmp << { name: '', value: '' }
tmp << {name: '', value: ''}
end
self.fields = tmp
@ -310,8 +310,8 @@ class Account < ApplicationRecord
def save_with_optional_media!
save!
rescue ActiveRecord::RecordInvalid
self.avatar = nil
self.header = nil
self.avatar = nil
self.header = nil
self[:avatar_remote_url] = ''
self[:header_remote_url] = ''
save!
@ -341,12 +341,12 @@ class Account < ApplicationRecord
attributes :name, :value, :verified_at, :account, :errors
def initialize(account, attributes)
@account = account
@attributes = attributes
@name = attributes['name'].strip[0, string_limit]
@value = attributes['value'].strip[0, string_limit]
@account = account
@attributes = attributes
@name = attributes['name'].strip[0, string_limit]
@value = attributes['value'].strip[0, string_limit]
@verified_at = attributes['verified_at']&.to_datetime
@errors = {}
@errors = {}
end
def verified?
@ -355,12 +355,12 @@ class Account < ApplicationRecord
def value_for_verification
@value_for_verification ||= begin
if account.local?
value
else
ActionController::Base.helpers.strip_tags(value)
end
end
if account.local?
value
else
ActionController::Base.helpers.strip_tags(value)
end
end
end
def verifiable?
@ -373,7 +373,7 @@ class Account < ApplicationRecord
end
def to_h
{ name: @name, value: @value, verified_at: @verified_at }
{name: @name, value: @value, verified_at: @verified_at}
end
private
@ -471,9 +471,9 @@ class Account < ApplicationRecord
private
def generate_query_for_search(terms)
terms = Arel.sql(connection.quote(terms.gsub(/['?\\:]/, ' ')))
terms = Arel.sql(connection.quote(terms.gsub(/['?\\:]/, ' ')))
textsearch = "(setweight(to_tsvector('simple', accounts.display_name), 'A') || setweight(to_tsvector('simple', accounts.username), 'B') || setweight(to_tsvector('simple', coalesce(accounts.domain, '')), 'C'))"
query = "to_tsquery('simple', ''' ' || #{terms} || ' ''' || ':*')"
query = "to_tsquery('simple', ''' ' || #{terms} || ' ''' || ':*')"
[textsearch, query]
end
@ -504,7 +504,7 @@ class Account < ApplicationRecord
keypair = OpenSSL::PKey::RSA.new(2048)
self.private_key = keypair.to_pem
self.public_key = keypair.public_key.to_pem
self.public_key = keypair.public_key.to_pem
end
def normalize_domain
@ -518,7 +518,7 @@ class Account < ApplicationRecord
end
def clean_feed_manager
reblog_key = FeedManager.instance.key(:home, id, 'reblogs')
reblog_key = FeedManager.instance.key(:home, id, 'reblogs')
reblogged_id_set = Redis.current.zrange(reblog_key, 0, -1)
Redis.current.pipelined do

View File

@ -25,6 +25,6 @@
%td
= number_to_human account.statuses_count, strip_insignificant_zeros: true
%td
= admin_account_link_to(account)
toudou
%td
= admin_account_link_to(account)
toudou

View File

@ -1,71 +1,72 @@
module.exports = (api) => {
const env = api.env();
module.exports = function(api) {
var validEnv = ['development', 'test', 'production']
var currentEnv = api.env()
var isDevelopmentEnv = api.env('development')
var isProductionEnv = api.env('production')
var isTestEnv = api.env('test')
const envOptions = {
debug: false,
loose: true,
modules: false,
};
const config = {
presets: [
'@babel/react',
['@babel/env', envOptions],
],
plugins: [
'@babel/syntax-dynamic-import',
['@babel/proposal-object-rest-spread', { useBuiltIns: true }],
['@babel/proposal-decorators', { legacy: true }],
'@babel/proposal-class-properties',
['react-intl', { messagesDir: './build/messages' }],
'preval',
],
overrides: [{
test: /tesseract\.js/,
presets: [
['@babel/env', { ...envOptions, modules: 'commonjs' }],
],
}],
};
switch (env) {
case 'production':
envOptions.debug = false;
config.plugins.push(...[
'lodash',
[
'transform-react-remove-prop-types',
{
mode: 'remove',
removeImport: true,
additionalLibraries: [
'react-immutable-proptypes',
],
},
],
'@babel/transform-react-inline-elements',
[
'@babel/transform-runtime',
{
helpers: true,
regenerator: false,
useESModules: true,
},
],
]);
break;
case 'development':
envOptions.debug = true;
config.plugins.push(...[
'@babel/transform-react-jsx-source',
'@babel/transform-react-jsx-self',
]);
break;
case 'test':
envOptions.modules = 'commonjs';
break;
if (!validEnv.includes(currentEnv)) {
throw new Error(
'Please specify a valid `NODE_ENV` or ' +
'`BABEL_ENV` environment variables. Valid values are "development", ' +
'"test", and "production". Instead, received: ' +
JSON.stringify(currentEnv) +
'.'
)
}
return config;
};
return {
presets: [
isTestEnv && [
require('@babel/preset-env').default,
{
targets: {
node: 'current'
}
}
],
(isProductionEnv || isDevelopmentEnv) && [
require('@babel/preset-env').default,
{
forceAllTransforms: true,
useBuiltIns: 'entry',
corejs: 3,
modules: false,
exclude: ['transform-typeof-symbol']
}
]
].filter(Boolean),
plugins: [
require('babel-plugin-macros'),
require('@babel/plugin-syntax-dynamic-import').default,
isTestEnv && require('babel-plugin-dynamic-import-node'),
require('@babel/plugin-transform-destructuring').default,
[
require('@babel/plugin-proposal-class-properties').default,
{
loose: true
}
],
[
require('@babel/plugin-proposal-object-rest-spread').default,
{
useBuiltIns: true
}
],
[
require('@babel/plugin-transform-runtime').default,
{
helpers: false,
regenerator: true,
corejs: false
}
],
[
require('@babel/plugin-transform-regenerator').default,
{
async: false
}
]
].filter(Boolean)
}
}

View File

@ -1,61 +1,5 @@
// Note: You must restart bin/webpack-dev-server for changes to take effect
process.env.NODE_ENV = process.env.NODE_ENV || 'development'
const merge = require('webpack-merge');
const sharedConfig = require('./shared');
const { settings, output } = require('./configuration');
const environment = require('./environment')
const watchOptions = {};
if (process.env.VAGRANT) {
// If we are in Vagrant, we can't rely on inotify to update us with changed
// files, so we must poll instead. Here, we poll every second to see if
// anything has changed.
watchOptions.poll = 1000;
}
module.exports = merge(sharedConfig, {
mode: 'development',
cache: true,
devtool: 'cheap-module-eval-source-map',
stats: {
errorDetails: true,
},
output: {
pathinfo: true,
},
devServer: {
clientLogLevel: 'none',
compress: settings.dev_server.compress,
quiet: settings.dev_server.quiet,
disableHostCheck: settings.dev_server.disable_host_check,
host: settings.dev_server.host,
port: settings.dev_server.port,
https: settings.dev_server.https,
hot: settings.dev_server.hmr,
contentBase: output.path,
inline: settings.dev_server.inline,
useLocalIp: settings.dev_server.use_local_ip,
public: settings.dev_server.public,
publicPath: output.publicPath,
historyApiFallback: {
disableDotRule: true,
},
headers: settings.dev_server.headers,
overlay: settings.dev_server.overlay,
stats: {
entrypoints: false,
errorDetails: false,
modules: false,
moduleTrace: false,
},
watchOptions: Object.assign(
{},
settings.dev_server.watch_options,
watchOptions
),
writeToDisk: filePath => /ocr/.test(filePath),
},
});
module.exports = environment.toWebpackConfig()

View File

@ -0,0 +1,3 @@
const { environment } = require('@rails/webpacker')
module.exports = environment

View File

@ -1,98 +1,5 @@
// Note: You must restart bin/webpack-dev-server for changes to take effect
process.env.NODE_ENV = process.env.NODE_ENV || 'production'
const path = require('path');
const { URL } = require('url');
const merge = require('webpack-merge');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const OfflinePlugin = require('offline-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const CompressionPlugin = require('compression-webpack-plugin');
const { output } = require('./configuration');
const sharedConfig = require('./shared');
const environment = require('./environment')
let attachmentHost;
if (process.env.S3_ENABLED === 'true') {
if (process.env.S3_ALIAS_HOST || process.env.S3_CLOUDFRONT_HOST) {
attachmentHost = process.env.S3_ALIAS_HOST || process.env.S3_CLOUDFRONT_HOST;
} else {
attachmentHost = process.env.S3_HOSTNAME || `s3-${process.env.S3_REGION || 'us-east-1'}.amazonaws.com`;
}
} else if (process.env.SWIFT_ENABLED === 'true') {
const { host } = new URL(process.env.SWIFT_OBJECT_URL);
attachmentHost = host;
} else {
attachmentHost = null;
}
module.exports = merge(sharedConfig, {
mode: 'production',
devtool: 'source-map',
stats: 'normal',
bail: true,
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
cache: true,
parallel: true,
sourceMap: true,
}),
],
},
plugins: [
new CompressionPlugin({
filename: '[path].gz[query]',
cache: true,
test: /\.(js|css|html|json|ico|svg|eot|otf|ttf|map)$/,
}),
new BundleAnalyzerPlugin({ // generates report.html
analyzerMode: 'static',
openAnalyzer: false,
logLevel: 'silent', // do not bother Webpacker, who runs with --json and parses stdout
}),
new OfflinePlugin({
publicPath: output.publicPath, // sw.js must be served from the root to avoid scope issues
safeToUseOptionalCaches: true,
caches: {
main: [':rest:'],
additional: [':externals:'],
optional: [
'**/locale_*.js', // don't fetch every locale; the user only needs one
'**/*_polyfills-*.js', // the user may not need polyfills
'**/*.woff2', // the user may have system-fonts enabled
// images/audio can be cached on-demand
'**/*.png',
'**/*.jpg',
'**/*.jpeg',
'**/*.svg',
'**/*.mp3',
'**/*.ogg',
],
},
externals: [
'/emoji/1f602.svg', // used for emoji picker dropdown
'/emoji/sheet_10.png', // used in emoji-mart
],
excludes: [
'**/*.gz',
'**/*.map',
'stats.json',
'report.html',
// any browser that supports ServiceWorker will support woff2
'**/*.eot',
'**/*.ttf',
'**/*-webfont-*.svg',
'**/*.woff',
],
ServiceWorker: {
entry: `imports-loader?ATTACHMENT_HOST=>${encodeURIComponent(JSON.stringify(attachmentHost))}!${encodeURI(path.join(__dirname, '../../app/javascript/mastodon/service_worker/entry.js'))}`,
cacheName: 'mastodon',
output: '../assets/sw.js',
publicPath: '/sw.js',
minify: true,
},
}),
],
});
module.exports = environment.toWebpackConfig()

View File

@ -1,8 +1,5 @@
// Note: You must restart bin/webpack-dev-server for changes to take effect
process.env.NODE_ENV = process.env.NODE_ENV || 'development'
const merge = require('webpack-merge');
const sharedConfig = require('./shared.js');
const environment = require('./environment')
module.exports = merge(sharedConfig, {
mode: 'development',
});
module.exports = environment.toWebpackConfig()

View File

@ -17,12 +17,13 @@ default: &default
cache_manifest: false
# Extract and emit a css file
extract_css: true
extract_css: false
static_assets_extensions:
- .jpg
- .jpeg
- .png
- .gif
- .tiff
- .ico
- .svg
@ -49,9 +50,11 @@ default: &default
development:
<<: *default
compile: true
# Verifies that correct packages and versions are installed by inspecting package.json, yarn.lock, and node_modules
check_yarn_integrity: true
# Reference: https://webpack.js.org/configuration/dev-server/
dev_server:
https: false
@ -71,12 +74,10 @@ development:
watch_options:
ignored: '**/node_modules/**'
test:
<<: *default
# CircleCI precompiles packs prior to running the tests.
# Also avoids race conditions in parallel_tests.
compile: false
compile: true
# Compile test packs to a separate directory
public_output_path: packs-test
@ -87,5 +88,8 @@ production:
# Production depends on precompilation of packs prior to booting for performance.
compile: false
# Extract and emit a css file
extract_css: true
# Cache manifest.json for performance
cache_manifest: true

View File

@ -72,6 +72,7 @@
"@babel/preset-react": "^7.0.0",
"@babel/runtime": "^7.5.4",
"@clusterws/cws": "^0.15.0",
"@rails/webpacker": "^4.2.0",
"array-includes": "^3.0.3",
"autoprefixer": "^9.6.1",
"axios": "^0.19.0",
@ -184,7 +185,7 @@
"react-intl-translations-manager": "^5.0.3",
"react-test-renderer": "^16.8.6",
"sass-lint": "^1.13.1",
"webpack-dev-server": "^3.8.0",
"webpack-dev-server": "^3.9.0",
"yargs": "^13.3.0"
}
}

View File

@ -1,7 +1,12 @@
module.exports = ({ env }) => ({
plugins: {
autoprefixer: {},
'postcss-object-fit-images': {},
cssnano: env === 'production' ? {} : false,
},
});
module.exports = {
plugins: [
require('postcss-import'),
require('postcss-flexbugs-fixes'),
require('postcss-preset-env')({
autoprefixer: {
flexbox: 'no-2009'
},
stage: 3
})
]
}

1997
yarn.lock

File diff suppressed because it is too large Load Diff