diff --git a/.nvmrc b/.nvmrc
index 1e8b314962..45a4fb75db 100644
--- a/.nvmrc
+++ b/.nvmrc
@@ -1 +1 @@
-6
+8
diff --git a/Aptfile b/Aptfile
index 5dac836079..60d24f8b31 100644
--- a/Aptfile
+++ b/Aptfile
@@ -5,6 +5,8 @@ libidn11
libidn11-dev
libpq-dev
libprotobuf-dev
+libssl-dev
libxdamage1
libxfixes3
protobuf-compiler
+zlib1g-dev
diff --git a/Dockerfile b/Dockerfile
index 77f39d9ec8..503696cf67 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,3 +1,4 @@
+FROM node:8.11.3-alpine as node
FROM ruby:2.4.4-alpine3.6
LABEL maintainer="https://github.com/tootsuite/mastodon" \
@@ -11,8 +12,6 @@ ENV PATH=/mastodon/bin:$PATH \
RAILS_ENV=production \
NODE_ENV=production
-ARG YARN_VERSION=1.3.2
-ARG YARN_DOWNLOAD_SHA256=6cfe82e530ef0837212f13e45c1565ba53f5199eec2527b85ecbcd88bf26821d
ARG LIBICONV_VERSION=1.15
ARG LIBICONV_DOWNLOAD_SHA256=ccf536620a45458d26ba83887a983b96827001e92a13847b45e4925cc8913178
@@ -20,6 +19,11 @@ EXPOSE 3000 4000
WORKDIR /mastodon
+COPY --from=node /usr/local/bin/node /usr/local/bin/node
+COPY --from=node /usr/local/lib/node_modules /usr/local/lib/node_modules
+COPY --from=node /usr/local/bin/npm /usr/local/bin/npm
+COPY --from=node /opt/yarn-* /opt/yarn
+
RUN apk -U upgrade \
&& apk add -t build-dependencies \
build-base \
@@ -39,20 +43,13 @@ RUN apk -U upgrade \
imagemagick \
libidn \
libpq \
- nodejs \
- nodejs-npm \
protobuf \
tini \
tzdata \
&& update-ca-certificates \
- && mkdir -p /tmp/src /opt \
- && wget -O yarn.tar.gz "https://github.com/yarnpkg/yarn/releases/download/v$YARN_VERSION/yarn-v$YARN_VERSION.tar.gz" \
- && echo "$YARN_DOWNLOAD_SHA256 *yarn.tar.gz" | sha256sum -c - \
- && tar -xzf yarn.tar.gz -C /tmp/src \
- && rm yarn.tar.gz \
- && mv /tmp/src/yarn-v$YARN_VERSION /opt/yarn \
&& ln -s /opt/yarn/bin/yarn /usr/local/bin/yarn \
&& ln -s /opt/yarn/bin/yarnpkg /usr/local/bin/yarnpkg \
+ && mkdir -p /tmp/src /opt \
&& wget -O libiconv.tar.gz "https://ftp.gnu.org/pub/gnu/libiconv/libiconv-$LIBICONV_VERSION.tar.gz" \
&& echo "$LIBICONV_DOWNLOAD_SHA256 *libiconv.tar.gz" | sha256sum -c - \
&& tar -xzf libiconv.tar.gz -C /tmp/src \
@@ -72,7 +69,7 @@ RUN rm /lib/stack-fix.c
RUN bundle config build.nokogiri --with-iconv-lib=/usr/local/lib --with-iconv-include=/usr/local/include \
&& bundle install -j$(getconf _NPROCESSORS_ONLN) --deployment --without test development \
- && yarn --pure-lockfile \
+ && yarn install --pure-lockfile --ignore-engines \
&& yarn cache clean
RUN addgroup -g ${GID} mastodon && adduser -h /mastodon -s /bin/sh -D -G mastodon -u ${UID} mastodon \
@@ -83,9 +80,11 @@ COPY . /mastodon
RUN chown -R mastodon:mastodon /mastodon
-VOLUME /mastodon/public/system /mastodon/public/assets /mastodon/public/packs
+VOLUME /mastodon/public/system
USER mastodon
ENV LD_PRELOAD=/lib/stack-fix.so
+RUN OTP_SECRET=precompile_placeholder SECRET_KEY_BASE=precompile_placeholder bundle exec rails assets:precompile
+
ENTRYPOINT ["/sbin/tini", "--"]
diff --git a/app/controllers/admin/relays_controller.rb b/app/controllers/admin/relays_controller.rb
new file mode 100644
index 0000000000..1b02d3c361
--- /dev/null
+++ b/app/controllers/admin/relays_controller.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+module Admin
+ class RelaysController < BaseController
+ before_action :set_relay, except: [:index, :new, :create]
+
+ def index
+ authorize :relay, :update?
+ @relays = Relay.all
+ end
+
+ def new
+ authorize :relay, :update?
+ @relay = Relay.new(inbox_url: Relay::PRESET_RELAY)
+ end
+
+ def create
+ authorize :relay, :update?
+
+ @relay = Relay.new(resource_params)
+
+ if @relay.save
+ @relay.enable!
+ redirect_to admin_relays_path
+ else
+ render action: :new
+ end
+ end
+
+ def destroy
+ authorize :relay, :update?
+ @relay.destroy
+ redirect_to admin_relays_path
+ end
+
+ def enable
+ authorize :relay, :update?
+ @relay.enable!
+ redirect_to admin_relays_path
+ end
+
+ def disable
+ authorize :relay, :update?
+ @relay.disable!
+ redirect_to admin_relays_path
+ end
+
+ private
+
+ def set_relay
+ @relay = Relay.find(params[:id])
+ end
+
+ def resource_params
+ params.require(:relay).permit(:inbox_url)
+ end
+ end
+end
diff --git a/app/helpers/stream_entries_helper.rb b/app/helpers/stream_entries_helper.rb
index a91a289355..05cea73d7b 100644
--- a/app/helpers/stream_entries_helper.rb
+++ b/app/helpers/stream_entries_helper.rb
@@ -67,7 +67,7 @@ module StreamEntriesHelper
end
def acct(account)
- if embedded_view? && account.local?
+ if account.local?
"@#{account.acct}@#{Rails.configuration.x.local_domain}"
else
"@#{account.acct}"
diff --git a/app/javascript/core/admin.js b/app/javascript/core/admin.js
index 28f27fbc62..3302454aba 100644
--- a/app/javascript/core/admin.js
+++ b/app/javascript/core/admin.js
@@ -1,6 +1,9 @@
// This file will be loaded on admin pages, regardless of theme.
import { delegate } from 'rails-ujs';
+import { start } from '../mastodon/common';
+
+start();
function handleDeleteStatus(event) {
const [data] = event.detail;
diff --git a/app/javascript/core/common.js b/app/javascript/core/common.js
index a7073ef0eb..3b038ca40c 100644
--- a/app/javascript/core/common.js
+++ b/app/javascript/core/common.js
@@ -1,8 +1,5 @@
// This file will be loaded on all pages, regardless of theme.
-import { start } from 'rails-ujs';
import 'font-awesome/css/font-awesome.css';
require.context('../images/', true);
-
-start();
diff --git a/app/javascript/flavours/glitch/packs/common.js b/app/javascript/flavours/glitch/packs/common.js
index 8dd4372bc4..94a4e6ee4e 100644
--- a/app/javascript/flavours/glitch/packs/common.js
+++ b/app/javascript/flavours/glitch/packs/common.js
@@ -1,3 +1,7 @@
+import { start } from 'rails-ujs';
+
+start();
+
import 'flavours/glitch/styles/index.scss';
// This ensures that webpack compiles our images.
diff --git a/app/javascript/mastodon/actions/domain_blocks.js b/app/javascript/mastodon/actions/domain_blocks.js
index 47e2df76ba..0445a5e10c 100644
--- a/app/javascript/mastodon/actions/domain_blocks.js
+++ b/app/javascript/mastodon/actions/domain_blocks.js
@@ -128,7 +128,7 @@ export function expandDomainBlocks() {
return (dispatch, getState) => {
const url = getState().getIn(['domain_lists', 'blocks', 'next']);
- if (url === null) {
+ if (!url) {
return;
}
diff --git a/app/javascript/mastodon/common.js b/app/javascript/mastodon/common.js
new file mode 100644
index 0000000000..2b10b8c30a
--- /dev/null
+++ b/app/javascript/mastodon/common.js
@@ -0,0 +1,8 @@
+import Rails from 'rails-ujs';
+
+export function start() {
+ require('font-awesome/css/font-awesome.css');
+ require.context('../images/', true);
+
+ Rails.start();
+};
diff --git a/app/javascript/mastodon/features/getting_started/index.js b/app/javascript/mastodon/features/getting_started/index.js
index 99642c9115..074ab01c8b 100644
--- a/app/javascript/mastodon/features/getting_started/index.js
+++ b/app/javascript/mastodon/features/getting_started/index.js
@@ -7,7 +7,7 @@ import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
-import { me, invitesEnabled } from '../../initial_state';
+import { me, invitesEnabled, version } from '../../initial_state';
import { fetchFollowRequests } from '../../actions/accounts';
import { List as ImmutableList } from 'immutable';
import { Link } from 'react-router-dom';
@@ -149,7 +149,7 @@ export default class GettingStarted extends ImmutablePureComponent {
tootsuite/mastodon }}
+ values={{ github: tootsuite/mastodon (v{version}) }}
/>
diff --git a/app/javascript/mastodon/features/ui/components/image_loader.js b/app/javascript/mastodon/features/ui/components/image_loader.js
index c7360a7264..5e1cf75af7 100644
--- a/app/javascript/mastodon/features/ui/components/image_loader.js
+++ b/app/javascript/mastodon/features/ui/components/image_loader.js
@@ -1,6 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
+import { LoadingBar } from 'react-redux-loading-bar';
import ZoomableImage from './zoomable_image';
export default class ImageLoader extends React.PureComponent {
@@ -23,6 +24,7 @@ export default class ImageLoader extends React.PureComponent {
state = {
loading: true,
error: false,
+ width: null,
}
removers = [];
@@ -122,6 +124,7 @@ export default class ImageLoader extends React.PureComponent {
setCanvasRef = c => {
this.canvas = c;
+ if (c) this.setState({ width: c.offsetWidth });
}
render () {
@@ -135,6 +138,7 @@ export default class ImageLoader extends React.PureComponent {
return (
+
{loading ? (