From: Thibaut Girka Date: Sat, 16 Mar 2019 12:52:55 +0000 (+0100) Subject: Merge branch 'master' into glitch-soc/merge-upstream X-Git-Url: https://git.xn--scling-oua.cat.family/?a=commitdiff_plain;h=4df3b7cb067797982199c3e613ba32a9c7474348;p=mastodon.git Merge branch 'master' into glitch-soc/merge-upstream Conflicts: - app/controllers/settings/follower_domains_controller.rb Removed upstream. Did the same here. Maybe we should not have? - config/locales/en.yml Upstream removed the “Authorized followers” page and associated translations. This is too close in the file to our glitch-soc-specific “flavour” string. No actual conflict. - config/locales/ja.yml Same as above. - config/locales/pl.yml Same as above. - config/navigation.rb No real conflict. New route added too close to the glitch-soc-specific “flavours” one. - config/webpack/configuration.js Upstream refactored the webpack(er) configuration quite a bit. Tried to keep up. - config/webpack/loaders/babel.js Upstream refactored the webpack(er) configuration quite a bit. Tried to keep up. The contents of this file have been moved to package.json. - config/webpack/shared.js Upstream refactored the webpack(er) configuration quite a bit. Tried to keep up. - config/webpacker.yml Upstream refactored the webpack(er) configuration quite a bit. Tried to keep up. - jest.config.js The contents of this file have been moved to package.json. - package.json Upstream refactored the webpack(er) configuration quite a bit. Tried to keep up. - yarn.lock Upstream refactored the webpack(er) configuration quite a bit. Tried to keep up. --- 4df3b7cb067797982199c3e613ba32a9c7474348 diff --cc Gemfile.lock index 2ebf7c5c3,e5542dd93..6ab8ae819 --- a/Gemfile.lock +++ b/Gemfile.lock @@@ -256,9 -258,8 +258,10 @@@ GE highline (2.0.0) hiredis (0.6.3) hkdf (0.3.0) + html2text (0.2.1) + nokogiri (~> 1.6) htmlentities (4.3.4) + http-2 (0.10.1) http (3.3.0) addressable (~> 2.3) http-cookie (~> 1.0) diff --cc app/serializers/rest/instance_serializer.rb index 97fed63d1,a82eff195..98c53c84a --- a/app/serializers/rest/instance_serializer.rb +++ b/app/serializers/rest/instance_serializer.rb @@@ -32,22 -32,9 +32,22 @@@ class REST::InstanceSerializer < Active end def thumbnail - instance_presenter.thumbnail ? full_asset_url(instance_presenter.thumbnail.file.url) : full_pack_url('preview.jpg') + instance_presenter.thumbnail ? full_asset_url(instance_presenter.thumbnail.file.url) : full_pack_url('media/images/preview.jpg') end + def max_toot_chars + StatusLengthValidator::MAX_CHARS + end + + def poll_limits + { + max_options: PollValidator::MAX_OPTIONS, + max_option_chars: PollValidator::MAX_OPTION_CHARS, + min_expiration: PollValidator::MIN_EXPIRATION, + max_expiration: PollValidator::MAX_EXPIRATION, + } + end + def stats { user_count: instance_presenter.user_count, diff --cc app/services/reblog_service.rb index 03db27406,ff48d9c75..deaa0549e --- a/app/services/reblog_service.rb +++ b/app/services/reblog_service.rb @@@ -17,14 -18,11 +18,14 @@@ class ReblogService < BaseServic return reblog unless reblog.nil? - reblog = account.statuses.create!(reblog: reblogged_status, text: '') + reblog = account.statuses.create!(reblog: reblogged_status, text: '', visibility: options[:visibility] || account.user&.setting_default_privacy) DistributionWorker.perform_async(reblog.id) - Pubsubhubbub::DistributionWorker.perform_async(reblog.stream_entry.id) - ActivityPub::DistributionWorker.perform_async(reblog.id) + + unless reblogged_status.local_only? + Pubsubhubbub::DistributionWorker.perform_async(reblog.stream_entry.id) + ActivityPub::DistributionWorker.perform_async(reblog.id) + end create_notification(reblog) bump_potential_friendship(account, reblog) diff --cc app/views/home/index.html.haml index 5f32635e5,4c7fac0b6..6c5268b61 --- a/app/views/home/index.html.haml +++ b/app/views/home/index.html.haml @@@ -7,9 -7,11 +7,9 @@@ %meta{name: 'applicationServerKey', content: Rails.configuration.x.vapid_public_key} %script#initial-state{ type: 'application/json' }!= json_escape(@initial_state_json) - = javascript_pack_tag 'application', integrity: true, crossorigin: 'anonymous' - .app-holder#mastodon{ data: { props: Oj.dump(default_props) } } %noscript - = image_tag asset_pack_path('logo.svg'), alt: 'Mastodon' + = image_pack_tag 'logo.svg', alt: 'Mastodon' %div = t('errors.noscript_html', apps_path: 'https://joinmastodon.org/apps') diff --cc config/locales/en.yml index 5dd9bb28b,4f9104eea..8a17d88e0 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@@ -839,8 -833,6 +837,7 @@@ en edit_profile: Edit profile export: Data export featured_tags: Featured hashtags + flavours: Flavours - followers: Authorized followers import: Import migrate: Account migration notifications: Notifications diff --cc config/locales/ja.yml index ace17a987,c3fa76530..e22359a32 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@@ -821,8 -808,6 +809,7 @@@ ja edit_profile: プロフィールを編集 export: データのエクスポート featured_tags: 注目のハッシュタグ + flavours: フレーバー - followers: 信頼済みのサーバー import: データのインポート migrate: アカウントの引っ越し notifications: 通知 diff --cc config/locales/pl.yml index b3ba6539d,878416dcf..e7f8e404d --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@@ -821,8 -806,6 +807,7 @@@ pl edit_profile: Edytuj profil export: Eksportowanie danych featured_tags: Wyróżnione hashtagi + flavours: Odmiany - followers: Autoryzowani śledzący import: Importowanie danych migrate: Migracja konta notifications: Powiadomienia diff --cc config/navigation.rb index f74c98ab2,77a300bbf..e730edfa2 --- a/config/navigation.rb +++ b/config/navigation.rb @@@ -14,15 -14,9 +14,15 @@@ SimpleNavigation::Configuration.run do settings.item :import, safe_join([fa_icon('cloud-upload fw'), t('settings.import')]), settings_import_url settings.item :export, safe_join([fa_icon('cloud-download fw'), t('settings.export')]), settings_export_url settings.item :authorized_apps, safe_join([fa_icon('list fw'), t('settings.authorized_apps')]), oauth_authorized_applications_url - settings.item :follower_domains, safe_join([fa_icon('users fw'), t('settings.followers')]), settings_follower_domains_url end + primary.item :flavours, safe_join([fa_icon('paint-brush fw'), t('settings.flavours')]), settings_flavours_url do |flavours| + Themes.instance.flavours.each do |flavour| + flavours.item flavour.to_sym, safe_join([fa_icon('star fw'), t("flavours.#{flavour}.name", default: flavour)]), settings_flavour_url(flavour) + end + end + + primary.item :relationships, safe_join([fa_icon('users fw'), t('settings.relationships')]), relationships_url primary.item :filters, safe_join([fa_icon('filter fw'), t('filters.index.title')]), filters_path, highlights_on: %r{/filters} primary.item :invites, safe_join([fa_icon('user-plus fw'), t('invites.title')]), invites_path, if: proc { Setting.min_invite_role == 'user' } diff --cc config/webpack/configuration.js index f81d23dd4,80a094c72..926af9b39 --- a/config/webpack/configuration.js +++ b/config/webpack/configuration.js @@@ -1,62 -1,15 +1,61 @@@ // Common configuration for webpacker loaded from config/webpacker.yml -const { resolve } = require('path'); +const { basename, dirname, extname, join, resolve } = require('path'); const { env } = require('process'); const { safeLoad } = require('js-yaml'); -const { readFileSync } = require('fs'); +const { lstatSync, readFileSync } = require('fs'); +const glob = require('glob'); const configPath = resolve('config', 'webpacker.yml'); - const loadersDir = join(__dirname, 'loaders'); const settings = safeLoad(readFileSync(configPath), 'utf8')[env.RAILS_ENV || env.NODE_ENV]; +const flavourFiles = glob.sync('app/javascript/flavours/*/theme.yml'); +const skinFiles = glob.sync('app/javascript/skins/*/*'); +const flavours = {}; -const themePath = resolve('config', 'themes.yml'); -const themes = safeLoad(readFileSync(themePath), 'utf8'); +const core = function () { + const coreFile = resolve('app', 'javascript', 'core', 'theme.yml'); + const data = safeLoad(readFileSync(coreFile), 'utf8'); + if (!data.pack_directory) { + data.pack_directory = dirname(coreFile); + } + return data.pack ? data : {}; +}(); + +for (let i = 0; i < flavourFiles.length; i++) { + const flavourFile = flavourFiles[i]; + const data = safeLoad(readFileSync(flavourFile), 'utf8'); + data.name = basename(dirname(flavourFile)); + data.skin = {}; + if (!data.pack_directory) { + data.pack_directory = dirname(flavourFile); + } + if (data.locales) { + data.locales = join(dirname(flavourFile), data.locales); + } + if (data.pack && typeof data.pack === 'object') { + flavours[data.name] = data; + } +} + +for (let i = 0; i < skinFiles.length; i++) { + const skinFile = skinFiles[i]; + let skin = basename(skinFile); + const name = basename(dirname(skinFile)); + if (!flavours[name]) { + continue; + } + const data = flavours[name].skin; + if (lstatSync(skinFile).isDirectory()) { + data[skin] = {}; + const skinPacks = glob.sync(join(skinFile, '*.{css,scss}')); + for (let j = 0; j < skinPacks.length; j++) { + const pack = skinPacks[j]; + data[skin][basename(pack, extname(pack))] = pack; + } + } else if ((skin = skin.match(/^(.*)\.s?css$/i))) { + data[skin[1]] = { common: skinFile }; + } +} function removeOuterSlashes(string) { return string.replace(/^\/*/, '').replace(/\/*$/, ''); diff --cc config/webpack/rules/babel.js index 000000000,2fc245c43..4d25748ee mode 000000,100644..100644 --- a/config/webpack/rules/babel.js +++ b/config/webpack/rules/babel.js @@@ -1,0 -1,21 +1,22 @@@ + const { join, resolve } = require('path'); + const { env, settings } = require('../configuration'); + + module.exports = { + test: /\.(js|jsx|mjs)$/, + include: [ + settings.source_path, + ...settings.resolved_paths, + ].map(p => resolve(p)), + exclude: /node_modules/, + use: [ + { + loader: 'babel-loader', + options: { ++ sourceRoot: 'app/javascript', + cacheDirectory: join(settings.cache_path, 'babel-loader'), + cacheCompression: env.NODE_ENV === 'production', + compact: env.NODE_ENV === 'production', + }, + }, + ], + }; diff --cc config/webpack/shared.js index 938bab9f5,cb4e5a85f..b6e2537b1 --- a/config/webpack/shared.js +++ b/config/webpack/shared.js @@@ -5,59 -5,38 +5,61 @@@ const { basename, dirname, join, relati const { sync } = require('glob'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const AssetsManifestPlugin = require('webpack-assets-manifest'); - const { env, settings, core, flavours, output, loadersDir } = require('./configuration.js'); -const extname = require('path-complete-extname'); -const { env, settings, themes, output } = require('./configuration'); ++const { env, settings, core, flavours, output } = require('./configuration.js'); + const rules = require('./rules'); -const localePackPaths = require('./generateLocalePacks'); +const localePacks = require('./generateLocalePacks'); + +function reducePacks (data, into = {}) { + if (!data.pack) { + return into; + } + Object.keys(data.pack).reduce((map, entry) => { + const pack = data.pack[entry]; + if (!pack) { + return map; + } + const packFile = typeof pack === 'string' ? pack : pack.filename; + if (packFile) { + map[data.name ? `flavours/${data.name}/${entry}` : `core/${entry}`] = resolve(data.pack_directory, packFile); + } + return map; + }, into); + if (data.name) { + Object.keys(data.skin).reduce((map, entry) => { + const skin = data.skin[entry]; + const skinName = entry; + if (!skin) { + return map; + } + Object.keys(skin).reduce((map, entry) => { + const packFile = skin[entry]; + if (!packFile) { + return map; + } + map[`skins/${data.name}/${skinName}/${entry}`] = resolve(packFile); + return map; + }, into); + return map; + }, into); + } + return into; +} + +const entries = Object.assign( + { locales: resolve('app', 'javascript', 'locales') }, + localePacks, + reducePacks(core), + Object.keys(flavours).reduce((map, entry) => reducePacks(flavours[entry], map), {}) +); -const extensionGlob = `**/*{${settings.extensions.join(',')}}*`; -const entryPath = join(settings.source_path, settings.source_entry_path); -const packPaths = sync(join(entryPath, extensionGlob)); module.exports = { - entry: Object.assign( - packPaths.reduce((map, entry) => { - const localMap = map; - const namespace = relative(join(entryPath), dirname(entry)); - localMap[join(namespace, basename(entry, extname(entry)))] = resolve(entry); - return localMap; - }, {}), - localePackPaths.reduce((map, entry) => { - const localMap = map; - localMap[basename(entry, extname(entry, extname(entry)))] = resolve(entry); - return localMap; - }, {}), - Object.keys(themes).reduce((themePaths, name) => { - themePaths[name] = resolve(join(settings.source_path, themes[name])); - return themePaths; - }, {}) - ), + entry: entries, output: { - filename: '[name].js', - chunkFilename: '[name].js', + filename: 'js/[name]-[chunkhash].js', + chunkFilename: 'js/[name]-[chunkhash].chunk.js', + hotUpdateChunkFilename: 'js/[id]-[hash].hot-update.js', path: output.path, publicPath: output.publicPath, }, diff --cc package.json index ecd9f86eb,63cfa25b8..b5963acd4 --- a/package.json +++ b/package.json @@@ -24,27 -24,55 +24,57 @@@ "iOS >= 9", "not dead" ], + "jest": { + "projects": [ + "/app/javascript/mastodon" + ], + "testPathIgnorePatterns": [ + "/node_modules/", + "/vendor/", + "/config/", + "/log/", + "/public/", - "/tmp/" ++ "/tmp/", ++ "/app/javascript/themes/" + ], + "setupFiles": [ + "raf/polyfill" + ], + "setupFilesAfterEnv": [ + "/app/javascript/mastodon/test_setup.js" + ], + "collectCoverageFrom": [ + "app/javascript/mastodon/**/*.js", + "!app/javascript/mastodon/features/emoji/emoji_compressed.js", + "!app/javascript/mastodon/locales/locale-data/*.js", + "!app/javascript/mastodon/service_worker/entry.js", + "!app/javascript/mastodon/test_setup.js" + ], + "coverageDirectory": "/coverage", + "moduleDirectories": [ + "/node_modules", + "/app/javascript" + ] + }, "private": true, "dependencies": { - "@babel/core": "^7.2.2", - "@babel/plugin-proposal-class-properties": "^7.2.3", - "@babel/plugin-proposal-decorators": "^7.2.3", - "@babel/plugin-proposal-object-rest-spread": "^7.2.0", + "@babel/core": "^7.3.4", + "@babel/plugin-proposal-class-properties": "^7.3.4", + "@babel/plugin-proposal-decorators": "^7.3.0", + "@babel/plugin-proposal-object-rest-spread": "^7.3.4", "@babel/plugin-syntax-dynamic-import": "^7.2.0", "@babel/plugin-transform-react-inline-elements": "^7.2.0", "@babel/plugin-transform-react-jsx-self": "^7.2.0", "@babel/plugin-transform-react-jsx-source": "^7.2.0", - "@babel/plugin-transform-runtime": "^7.2.0", - "@babel/preset-env": "^7.2.3", + "@babel/plugin-transform-runtime": "^7.3.4", + "@babel/preset-env": "^7.3.4", "@babel/preset-react": "^7.0.0", - "@babel/runtime": "^7.2.0", - "@gfx/zopfli": "^1.0.10", + "@babel/runtime": "^7.3.4", "array-includes": "^3.0.3", + "atrament": "^0.2.3", - "autoprefixer": "^9.4.3", + "autoprefixer": "^9.4.10", "axios": "^0.18.0", - "babel-core": "^7.0.0-bridge.0", - "babel-loader": "^8.0.4", + "babel-loader": "^8.0.5", "babel-plugin-lodash": "^3.3.4", "babel-plugin-preval": "^3.0.1", "babel-plugin-react-intl": "^3.0.1", diff --cc yarn.lock index 3137b0856,9d7f0eccb..11fe49fa6 --- a/yarn.lock +++ b/yarn.lock @@@ -1272,20 -1526,16 +1526,20 @@@ atob@^2.1.1 resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== +atrament@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/atrament/-/atrament-0.2.3.tgz#6ccbc0daa6d3f25e5aeaeb31befeb78e86980348" + - autoprefixer@^9.4.3: - version "9.4.3" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.4.3.tgz#c97384a8fd80477b78049163a91bbc725d9c41d9" - integrity sha512-/XSnzDepRkAU//xLcXA/lUWxpsBuw0WiriAHOqnxkuCtzLhaz+fL4it4gp20BQ8n5SyLzK/FOc7A0+u/rti2FQ== + autoprefixer@^9.4.10: + version "9.4.10" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.4.10.tgz#e1be61fc728bacac8f4252ed242711ec0dcc6a7b" + integrity sha512-XR8XZ09tUrrSzgSlys4+hy5r2/z4Jp7Ag3pHm31U4g/CTccYPOVe19AkaJ4ey/vRd1sfj+5TtuD6I0PXtutjvQ== dependencies: - browserslist "^4.3.6" - caniuse-lite "^1.0.30000921" + browserslist "^4.4.2" + caniuse-lite "^1.0.30000940" normalize-range "^0.1.2" num2fraction "^1.2.2" - postcss "^7.0.6" + postcss "^7.0.14" postcss-value-parser "^3.3.1" aws-sign2@~0.7.0: @@@ -3627,15 -3720,6 +3724,10 @@@ fast-levenshtein@~2.0.4 resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= - fastparse@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.2.tgz#91728c5a5942eced8531283c79441ee4122c35a9" - integrity sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ== - +favico.js@^0.3.10: + version "0.3.10" + resolved "https://registry.yarnpkg.com/favico.js/-/favico.js-0.3.10.tgz#80586e27a117f24a8d51c18a99bdc714d4339301" + faye-websocket@^0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4"