Merge branch 'master' into skylight

This commit is contained in:
Eugen Rochko 2017-04-05 20:00:21 +02:00
commit 31e086de0e
15 changed files with 162 additions and 29 deletions

2
.buildpacks Normal file
View file

@ -0,0 +1,2 @@
https://github.com/Scalingo/nodejs-buildpack
https://github.com/Scalingo/ruby-buildpack

2
.slugignore Normal file
View file

@ -0,0 +1,2 @@
node_modules/
.cache/

View file

@ -117,6 +117,12 @@ Which will re-create the updated containers, leaving databases and data as is. D
Docker is great for quickly trying out software, but it has its drawbacks too. If you prefer to run Mastodon without using Docker, refer to the [production guide](docs/Running-Mastodon/Production-guide.md) for examples, configuration and instructions. Docker is great for quickly trying out software, but it has its drawbacks too. If you prefer to run Mastodon without using Docker, refer to the [production guide](docs/Running-Mastodon/Production-guide.md) for examples, configuration and instructions.
## Deployment on Scalingo
[![Deploy on Scalingo](https://cdn.scalingo.com/deploy/button.svg)](https://my.scalingo.com/deploy?source=https://github.com/tootsuite/mastodon#master)
[You can view a guide for deployment on Scalingo here.](docs/Running-Mastodon/Scalingo-guide.md)
## Deployment on Heroku (experimental) ## Deployment on Heroku (experimental)
[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy) [![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy)

View file

@ -34,12 +34,7 @@ class FeedManager
trim(timeline_type, account.id) trim(timeline_type, account.id)
end end
broadcast(account.id, event: 'update', payload: inline_render(account, 'api/v1/statuses/show', status)) PushUpdateWorker.perform_async(account.id, status.id)
end
def broadcast(timeline_id, options = {})
options[:queued_at] = (Time.now.to_f * 1000.0).to_i
redis.publish("timeline:#{timeline_id}", Oj.dump(options))
end end
def trim(type, account_id) def trim(type, account_id)
@ -81,10 +76,6 @@ class FeedManager
end end
end end
def inline_render(target_account, template, object)
Rabl::Renderer.new(template, object, view_path: 'app/views', format: :json, scope: InlineRablScope.new(target_account)).render
end
private private
def redis def redis

View file

@ -0,0 +1,13 @@
# frozen_string_literal: true
class InlineRenderer
def self.render(status, current_account, template)
Rabl::Renderer.new(
template,
status,
view_path: 'app/views',
format: :json,
scope: InlineRablScope.new(current_account)
).render
end
end

View file

@ -50,22 +50,22 @@ class FanOutOnWriteService < BaseService
end end
def render_anonymous_payload(status) def render_anonymous_payload(status)
@payload = FeedManager.instance.inline_render(nil, 'api/v1/statuses/show', status) @payload = InlineRenderer.render(status, nil, 'api/v1/statuses/show')
end end
def deliver_to_hashtags(status) def deliver_to_hashtags(status)
Rails.logger.debug "Delivering status #{status.id} to hashtags" Rails.logger.debug "Delivering status #{status.id} to hashtags"
status.tags.pluck(:name).each do |hashtag| status.tags.pluck(:name).each do |hashtag|
FeedManager.instance.broadcast("hashtag:#{hashtag}", event: 'update', payload: @payload) Redis.current.publish("hashtag:#{hashtag}", Oj.dump(event: :update, payload: @payload))
FeedManager.instance.broadcast("hashtag:#{hashtag}:local", event: 'update', payload: @payload) if status.account.local? Redis.current.publish("hashtag:#{hashtag}:local", Oj.dump(event: :update, payload: @payload)) if status.account.local?
end end
end end
def deliver_to_public(status) def deliver_to_public(status)
Rails.logger.debug "Delivering status #{status.id} to public timeline" Rails.logger.debug "Delivering status #{status.id} to public timeline"
FeedManager.instance.broadcast(:public, event: 'update', payload: @payload) Redis.current.publish('public', Oj.dump(event: 'update', payload: @payload))
FeedManager.instance.broadcast('public:local', event: 'update', payload: @payload) if status.account.local? Redis.current.publish('public:local', Oj.dump(event: 'update', payload: @payload)) if status.account.local?
end end
end end

View file

@ -50,7 +50,7 @@ class NotifyService < BaseService
def create_notification def create_notification
@notification.save! @notification.save!
return unless @notification.browserable? return unless @notification.browserable?
FeedManager.instance.broadcast(@recipient.id, event: 'notification', payload: FeedManager.instance.inline_render(@recipient, 'api/v1/notifications/show', @notification)) Redis.current.publish(@recipient.id, Oj.dump(event: :notification, payload: InlineRenderer.render(@notification, @recipient, 'api/v1/notifications/show')))
end end
def send_email def send_email

View file

@ -65,17 +65,17 @@ class RemoveStatusService < BaseService
redis.zremrangebyscore(FeedManager.instance.key(type, receiver.id), status.id, status.id) redis.zremrangebyscore(FeedManager.instance.key(type, receiver.id), status.id, status.id)
end end
FeedManager.instance.broadcast(receiver.id, event: 'delete', payload: status.id) Redis.current.publish(receiver.id, Oj.dump(event: :delete, payload: status.id))
end end
def remove_from_hashtags(status) def remove_from_hashtags(status)
status.tags.each do |tag| status.tags.each do |tag|
FeedManager.instance.broadcast("hashtag:#{tag.name}", event: 'delete', payload: status.id) Redis.current.publish("hashtag:#{tag.name}", Oj.dump(event: :delete, payload: status.id))
end end
end end
def remove_from_public(status) def remove_from_public(status)
FeedManager.instance.broadcast(:public, event: 'delete', payload: status.id) Redis.current.publish('public', Oj.dump(event: :delete, payload: status.id))
end end
def redis def redis

View file

@ -0,0 +1,15 @@
# frozen_string_literal: true
class PushUpdateWorker
include Sidekiq::Worker
def perform(account_id, status_id)
account = Account.find(account_id)
status = Status.find(status_id)
message = InlineRenderer.render(status, account, 'api/v1/statuses/show')
Redis.current.publish("timeline:#{account.id}", Oj.dump(event: :update, payload: message, queued_at: (Time.now.to_f * 1000.0).to_i))
rescue ActiveRecord::RecordNotFound
true
end
end

View file

@ -1,4 +1,5 @@
Rabl.configure do |config| Rabl.configure do |config|
config.json_engine = Oj
config.cache_all_output = false config.cache_all_output = false
config.cache_sources = Rails.env.production? config.cache_sources = Rails.env.production?
config.include_json_root = false config.include_json_root = false

View file

@ -21,12 +21,12 @@ fi:
features_headline: Mikä erottaa Mastodonin muista features_headline: Mikä erottaa Mastodonin muista
get_started: Aloita käyttö get_started: Aloita käyttö
links: Linkit links: Linkit
other_instances: Muut palvelimet other_instances: muuhun palvelimeen
source_code: Lähdekoodi source_code: Lähdekoodi
status_count_after: statukset status_count_after: statusta
status_count_before: Kuka loi status_count_before: Ovat luoneet
terms: Ehdot terms: Ehdot
user_count_after: käyttäjät user_count_after: käyttäjää
user_count_before: Koti käyttäjälle user_count_before: Koti käyttäjälle
accounts: accounts:
follow: Seuraa follow: Seuraa
@ -89,7 +89,7 @@ fi:
preface: Voit tuoda tiettyä dataa kaikista ihmisistä joita seuraat tai estät tilillesi tälle palvelimelle tiedostoista, jotka on luotu toisella palvelimella preface: Voit tuoda tiettyä dataa kaikista ihmisistä joita seuraat tai estät tilillesi tälle palvelimelle tiedostoista, jotka on luotu toisella palvelimella
success: Datasi on onnistuneesti ladattu ja käsitellään pian success: Datasi on onnistuneesti ladattu ja käsitellään pian
types: types:
blocking: Esto lista blocking: Estetyt lista
following: Seuratut lista following: Seuratut lista
upload: Lähetä upload: Lähetä
landing_strip_html: <strong>%{name}</strong> on käyttäjä domainilla <strong>%{domain}</strong>. Voit seurata tai vuorovaikuttaa heidän kanssaan jos sinulla on tili yleisessä verkossa. Jos sinulla ei ole tiliä, voit <a href="%{sign_up_path}">rekisteröityä täällä</a>. landing_strip_html: <strong>%{name}</strong> on käyttäjä domainilla <strong>%{domain}</strong>. Voit seurata tai vuorovaikuttaa heidän kanssaan jos sinulla on tili yleisessä verkossa. Jos sinulla ei ole tiliä, voit <a href="%{sign_up_path}">rekisteröityä täällä</a>.
@ -132,7 +132,7 @@ fi:
edit_profile: Muokkaa profiilia edit_profile: Muokkaa profiilia
export: Datan vienti export: Datan vienti
import: Datan tuonti import: Datan tuonti
preferences: Mieltymykset preferences: Ominaisuudet
settings: Asetukset settings: Asetukset
two_factor_auth: Kaksivaiheinen tunnistus two_factor_auth: Kaksivaiheinen tunnistus
statuses: statuses:
@ -154,7 +154,7 @@ fi:
description_html: Jos otat käyttöön <strong>kaksivaiheisen tunnistuksen</stron>, kirjautumiseen vaaditaan puhelin, joka voi generoida tokeneita kirjautumista varten. description_html: Jos otat käyttöön <strong>kaksivaiheisen tunnistuksen</stron>, kirjautumiseen vaaditaan puhelin, joka voi generoida tokeneita kirjautumista varten.
disable: Poista käytöstä disable: Poista käytöstä
enable: Ota käyttöön enable: Ota käyttöön
instructions_html: "<strong>Skannaa tämä QR-koodi Google Authenticator tai samanlaiseen sovellukseen puhelimellasi</strong>. Tästä hetkestä lähtien, ohjelma generoi tokenit mikä sinun tarvitsee syöttää sisäänkirjautuessa." instructions_html: "<strong>Skannaa tämä QR-koodi Google Authenticator tai samanlaiseen sovellukseen puhelimellasi</strong>. Tästä hetkestä lähtien ohjelma generoi koodin, mikä sinun tarvitsee syöttää sisäänkirjautuessa."
plaintext_secret_html: 'Plain-text secret: <samp>%{secret}</samp>' plaintext_secret_html: 'Plain-text secret: <samp>%{secret}</samp>'
warning: Jos et juuri nyt voi konfiguroida authenticator-applikaatiota juuri nyt, sinun pitäisi klikata "Poista käytöstä" tai et voi kirjautua sisään. warning: Jos et juuri nyt voi konfiguroida authenticator-applikaatiota juuri nyt, sinun pitäisi klikata "Poista käytöstä" tai et voi kirjautua sisään.
users: users:

View file

@ -88,8 +88,9 @@ It is recommended to create a special user for mastodon on the server (you could
## General dependencies ## General dependencies
sudo apt-get install imagemagick ffmpeg libpq-dev libxml2-dev libxslt1-dev nodejs file git curl
curl -sL https://deb.nodesource.com/setup_4.x | sudo bash - curl -sL https://deb.nodesource.com/setup_4.x | sudo bash -
sudo apt-get install imagemagick ffmpeg libpq-dev libxml2-dev libxslt1-dev nodejs file apt-get intall nodejs
sudo npm install -g yarn sudo npm install -g yarn
## Redis ## Redis

View file

@ -0,0 +1,13 @@
Scalingo guide
==============
[![Deploy on Scalingo](https://cdn.scalingo.com/deploy/button.svg)](https://my.scalingo.com/deploy?source=https://github.com/tootsuite/mastodon#master)
1. Click the above button.
2. Fill in the options requested.
* You can use a .scalingo.io domain, which will be simple to set up, or you can use a custom domain.
* You will want Amazon S3 for file storage. The only exception is for development purposes, where you may not care if files are not saved. Follow a guide online for creating a free Amazon S3 bucket and Access Key, then enter the details.
* If you want your Mastodon to be able to send emails, configure SMTP settings here (or later). Consider using [Mailgun](https://mailgun.com) or similar, who offer free plans that should suit your interests.
3. Deploy! The app should be set up, with a working web interface and database. You can change settings and manage versions from the Heroku dashboard.
You may need to use the `scalingo` CLI application to run `USERNAME=yourUsername rails mastodon:make_admin` to make yourself an admin.

View file

@ -20,14 +20,15 @@ There is also a list at [instances.mastodon.xyz](https://instances.mastodon.xyz)
| [social.diskseven.com](https://social.diskseven.com) |Single user|No|Yes| | [social.diskseven.com](https://social.diskseven.com) |Single user|No|Yes|
| [social.gestaltzerfall.net](https://social.gestaltzerfall.net) |Single user|No|No| | [social.gestaltzerfall.net](https://social.gestaltzerfall.net) |Single user|No|No|
| [mastodon.xyz](https://mastodon.xyz) |N/A|Yes|Yes| | [mastodon.xyz](https://mastodon.xyz) |N/A|Yes|Yes|
| [mastodon.partipirate.org](https://mastodon.partipirate.org) |French Pirate Part Instance - Politics and stuff|Yes|No| | [mastodon.partipirate.org](https://mastodon.partipirate.org) |French Pirate Party Instance - Politics and stuff|Yes|No|
| [social.targaryen.house](https://social.targaryen.house) |Federates everywhere, quick updates.|Yes|Yes| | [social.targaryen.house](https://social.targaryen.house) |Federates everywhere, quick updates.|Yes|Yes|
| [masto.themimitoof.fr](https://masto.themimitoof.fr) |N/A|Yes|Yes| | [masto.themimitoof.fr](https://masto.themimitoof.fr) |N/A|Yes|Yes|
| [mstdn.io](https://mstdn.io) |N/A|Yes|Yes| | [mstdn.io](https://mstdn.io) |N/A|Yes|Yes|
| [social.imirhil.fr](https://social.imirhil.fr) |N/A|No|Yes| | [social.imirhil.fr](https://social.imirhil.fr) |N/A|No|Yes|
| [social.wxcafe.net](https://social.wxcafe.net) |Open registrations, federates everywhere, no moderation yet|Yes|Yes| | [social.wxcafe.net](https://social.wxcafe.net) |Open registrations, queer people, activists, safe as much as possible |Yes|Yes|
| [octodon.social](https://octodon.social) |Open registrations, federates everywhere, cutest instance yet|Yes|Yes| | [octodon.social](https://octodon.social) |Open registrations, federates everywhere, cutest instance yet|Yes|Yes|
| [mastodon.club](https://mastodon.club)|Open Registration, Open Federation, Mostly Canadians|Yes|No| | [mastodon.club](https://mastodon.club)|Open Registration, Open Federation, Mostly Canadians|Yes|No|
| [mastodon.irish](https://mastodon.irish)|Open Registration|Yes|No|
| [hostux.social](https://hostux.social) |N/A|Yes|Yes| | [hostux.social](https://hostux.social) |N/A|Yes|Yes|
| [social.alex73630.xyz](https://social.alex73630.xyz) |Francophones|Yes|Yes| | [social.alex73630.xyz](https://social.alex73630.xyz) |Francophones|Yes|Yes|
| [oc.todon.fr](https://oc.todon.fr) |Modérée et principalement francophone, pas de tolérances pour misogynie/LGBTphobies/validisme/etc.|Yes|Yes| | [oc.todon.fr](https://oc.todon.fr) |Modérée et principalement francophone, pas de tolérances pour misogynie/LGBTphobies/validisme/etc.|Yes|Yes|
@ -46,5 +47,6 @@ There is also a list at [instances.mastodon.xyz](https://instances.mastodon.xyz)
| [status.dissidence.ovh](https://status.dissidence.ovh)|N/A|Yes|Yes| | [status.dissidence.ovh](https://status.dissidence.ovh)|N/A|Yes|Yes|
| [mastodon.cc](https://mastodon.cc)|Art|Yes|No| | [mastodon.cc](https://mastodon.cc)|Art|Yes|No|
| [mastodon.technology](https://mastodon.technology)|Open registrations, federates everywhere, for tech folks|Yes|No| | [mastodon.technology](https://mastodon.technology)|Open registrations, federates everywhere, for tech folks|Yes|No|
| [mastodon.systemlab.fr](https://mastodon.systemlab.fr/)|Le mastodon Français, informatique, jeux-vidéos, gaming et hébergement.|Yes|No|
Let me know if you start running one so I can add it to the list! (Alternatively, add it yourself as a pull request). Let me know if you start running one so I can add it to the list! (Alternatively, add it yourself as a pull request).

87
scalingo.json Normal file
View file

@ -0,0 +1,87 @@
{
"name": "Mastodon",
"description": "A GNU Social-compatible microblogging server",
"repository": "https://github.com/johnsudaar/mastodon",
"logo": "https://github.com/tootsuite/mastodon/raw/master/app/assets/images/logo.png",
"env": {
"LOCAL_DOMAIN": {
"description": "The domain that your Mastodon instance will run on (this can be appname.scalingo.io or a custom domain)",
"required": true
},
"LOCAL_HTTPS": {
"description": "Will your domain support HTTPS? (Automatic for *.scalingo.io, requires manual configuration for custom domains)",
"value": "true",
"required": true
},
"PAPERCLIP_SECRET": {
"description": "The secret key for storing media files",
"generator": "secret"
},
"SECRET_KEY_BASE": {
"description": "The secret key base",
"generator": "secret"
},
"SINGLE_USER_MODE": {
"description": "Should the instance run in single user mode? (Disable registrations, redirect to front page)",
"value": "false",
"required": true
},
"S3_ENABLED": {
"description": "Should Mastodon use Amazon S3 for storage? This is highly recommended, as Scalingo does not have persistent file storage (files will be lost).",
"value": "true",
"required": false
},
"S3_BUCKET": {
"description": "Amazon S3 Bucket",
"required": false
},
"S3_REGION": {
"description": "Amazon S3 region that the bucket is located in",
"required": false
},
"AWS_ACCESS_KEY_ID": {
"description": "Amazon S3 Access Key",
"required": false
},
"AWS_SECRET_ACCESS_KEY": {
"description": "Amazon S3 Secret Key",
"required": false
},
"SMTP_SERVER": {
"description": "Hostname for SMTP server, if you want to enable email",
"required": false
},
"SMTP_PORT": {
"description": "Port for SMTP server",
"required": false
},
"SMTP_LOGIN": {
"description": "Username for SMTP server",
"required": false
},
"SMTP_PASSWORD": {
"description": "Password for SMTP server",
"required": false
},
"SMTP_DOMAIN": {
"description": "Domain for SMTP server. Will default to instance domain if blank.",
"required": false
},
"SMTP_FROM_ADDRESS": {
"description": "Address to send emails from",
"required": false
},
"BUILDPACK_URL": {
"description": "Internal scalingo configuration",
"required": true,
"value": "https://github.com/Scalingo/multi-buildpack.git"
}
},
"scripts": {
"postdeploy": "bundle exec rails db:migrate && bundle exec rails db:seed"
},
"addons": [
"scalingo-postgresql",
"scalingo-redis"
]
}