Compare commits

..

2 Commits

41 changed files with 86 additions and 295 deletions

View File

@@ -36,8 +36,7 @@ OTP_SECRET=
# E-mail configuration
# Note: Mailgun and SparkPost (https://sparkpo.st/smtp) each have good free tiers
# If you want to use an SMTP server without authentication (e.g local Postfix relay)
# then set SMTP_AUTH_METHOD to 'none' and *comment* SMTP_LOGIN and SMTP_PASSWORD.
# Leaving them blank is not enough for authentication method 'none'.
# then set SMTP_AUTH_METHOD to 'none' and leave SMTP_LOGIN and SMTP_PASSWORD blank
SMTP_SERVER=smtp.mailgun.org
SMTP_PORT=587
SMTP_LOGIN=

View File

@@ -1,7 +1,5 @@
language: ruby
cache: bundler
dist: trusty
sudo: required
notifications:
email: false
@@ -26,9 +24,8 @@ bundler_args: --without development production --retry=3 --jobs=3
before_install:
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
- sudo add-apt-repository -y ppa:mc3man/trusty-media
- sudo apt-get -qq update
- sudo apt-get -qq install g++-4.8 ffmpeg
- sudo apt-get -qq install g++-4.8
install:
- nvm install
- npm install -g yarn

View File

@@ -44,10 +44,7 @@ const Button = React.createClass({
cursor: 'pointer',
lineHeight: `${this.props.size}px`,
borderRadius: '4px',
textDecoration: 'none',
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
overflow: 'hidden'
textDecoration: 'none'
};
return (

View File

@@ -48,7 +48,6 @@ import es from 'react-intl/locale-data/es';
import fi from 'react-intl/locale-data/fi';
import fr from 'react-intl/locale-data/fr';
import hu from 'react-intl/locale-data/hu';
import it from 'react-intl/locale-data/it';
import ja from 'react-intl/locale-data/ja';
import pt from 'react-intl/locale-data/pt';
import nl from 'react-intl/locale-data/nl';
@@ -79,7 +78,6 @@ addLocaleData([
...fi,
...fr,
...hu,
...it,
...ja,
...pt,
...pt_br,

View File

@@ -197,9 +197,9 @@ const ComposeForm = React.createClass({
<SpoilerButtonContainer />
</div>
<div style={{ display: 'flex', minWidth: 0 }}>
<div style={{ display: 'flex' }}>
<div style={{ paddingTop: '10px', marginRight: '16px', lineHeight: '36px' }}><CharacterCounter max={500} text={text} /></div>
<div style={{ paddingTop: '10px', overflow: 'hidden' }}><Button text={publishText} onClick={this.handleSubmit} disabled={disabled || text.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, "_").length > 500} block /></div>
<div style={{ paddingTop: '10px' }}><Button text={publishText} onClick={this.handleSubmit} disabled={disabled || text.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, "_").length > 500} /></div>
</div>
</div>
</div>

View File

@@ -53,7 +53,7 @@ const SearchResults = React.createClass({
return (
<div className='search-results'>
<div className='search-results__header'>
<FormattedMessage id='search_results.total' defaultMessage='{count, number} {count, plural, one {result} other {results}}' values={{ count }} />
<FormattedMessage id='search_results.total' defaultMessage='{count} {count, plural, one {result} other {results}}' values={{ count }} />
</div>
{accounts}

View File

@@ -100,7 +100,7 @@ const en = {
"report.placeholder": "Additional comments",
"report.submit": "Submit",
"report.target": "Reporting",
"search_results.total": "{count, number} {count, plural, one {result} other {results}}",
"search_results.total": "{count} {count, plural, one {result} other {results}}",
"search.placeholder": "Search",
"search.status_by": "Status by {name}",
"status.delete": "Delete",

View File

@@ -35,10 +35,6 @@ const es = {
"column.community": "Historia local",
"column.public": "Historia federada",
"column.notifications": "Notificaciones",
"column.blocks": "Usuarios bloqueados",
"column.favourites": "Favoritos",
"column.follow_requests": "Solicitudes para seguirte",
"column.mutes": "Usuarios silenciados",
"tabs_bar.compose": "Redactar",
"tabs_bar.home": "Inicio",
"tabs_bar.mentions": "Menciones",
@@ -60,8 +56,6 @@ const es = {
"navigation_bar.blocks": "Usuarios bloqueados",
"navigation_bar.info": "Información adicional",
"navigation_bar.logout": "Cerrar sesión",
"navigation_bar.follow_requests": "Solicitudes para seguirte",
"navigation_bar.mutes": "Usuarios silenciados",
"reply_indicator.cancel": "Cancelar",
"search.placeholder": "Buscar",
"search.account": "Cuenta",

View File

@@ -81,7 +81,7 @@ const fr = {
"search.placeholder": "Rechercher",
"search.account": "Compte",
"search.hashtag": "Mot-clé",
"search_results.total": "{count, number} {count, plural, one {résultat} other {résultats}}",
"search_results.total": "{count} {count, plural, one {résultat} other {résultats}}",
"search.status_by": "Statuts de {name}",
"upload_button.label": "Joindre un média",
"upload_form.undo": "Annuler",

View File

@@ -90,7 +90,7 @@ const hr = {
"report.placeholder": "Dodatni komentari",
"report.submit": "Pošalji",
"report.target": "Prijavljivanje",
"search_results.total": "{count, number} {count, plural, one {result} other {results}}",
"search_results.total": "{count} {count, plural, one {result} other {results}}",
"search.placeholder": "Traži",
"search.status_by": "Status od {name}",
"status.delete": "Obriši",

View File

@@ -18,7 +18,7 @@ const hu = {
"account.block": "Blokkolás",
"account.follow": "Követés",
"account.posts": "Posts",
"account.follows": "Követve",
"account.follows": "Követők",
"account.followers": "Követők",
"account.follows_you": "Követnek téged",
"getting_started.heading": "Első lépések",

View File

@@ -3,7 +3,6 @@ import de from './de';
import es from './es';
import hr from './hr';
import hu from './hu';
import it from './it';
import fr from './fr';
import nl from './nl';
import no from './no';
@@ -24,7 +23,6 @@ const locales = {
es,
hr,
hu,
it,
fr,
nl,
no,

View File

@@ -1,125 +0,0 @@
const it = {
"account.block": "Blocca @{name}",
"account.disclaimer": "Questo utente si trova su un altro server. Questo numero potrebbe essere maggiore.",
"account.edit_profile": "Modifica profilo",
"account.follow": "Segui",
"account.followers": "Seguaci",
"account.follows_you": "Ti segue",
"account.follows": "Segue",
"account.mention": "Menziona @{name}",
"account.mute": "Silenzia @{name}",
"account.posts": "Posts",
"account.report": "Segnala @{name}",
"account.requested": "In attesa di approvazione",
"account.unblock": "Sblocca @{name}",
"account.unfollow": "Non seguire",
"account.unmute": "Non silenziare @{name}",
"boost_modal.combo": "Puoi premere {combo} per saltare questo passaggio la prossima volta",
"column_back_button.label": "Indietro",
"column.blocks": "Utenti bloccati",
"column.community": "Timeline locale",
"column.favourites": "Apprezzati",
"column.follow_requests": "Richieste di amicizia",
"column.home": "Home",
"column.mutes": "Utenti silenziati",
"column.notifications": "Notifiche",
"column.public": "Timeline federata",
"compose_form.placeholder": "A cosa stai pensando?",
"compose_form.privacy_disclaimer": "Il tuo status privato verrà condiviso con gli utenti menzionati su {domains}. Ti fidi di {domainsCount, plural, one {quel server} other {quei server}}? Le impostazioni sulla privacy valgono solo su server Mastodon. Se {domains} {domainsCount, plural, one {non è un server Mastodon} other {non sono server Mastodon}}, non ci saranno indicazioni sulla privacy del tuo status, e potrebbe essere condiviso o reso visibile a destinatari indesiderati.",
"compose_form.publish": "Toot",
"compose_form.sensitive": "Segnala file come sensibile",
"compose_form.spoiler_placeholder": "Content warning",
"compose_form.spoiler": "Nascondi testo con avvertimento",
"emoji_button.label": "Inserisci emoji",
"empty_column.community": "La timeline locale è vuota. Condividi qualcosa pubblicamente per dare inizio alla festa!",
"empty_column.hashtag": "Non c'è ancora nessun post con questo hashtag.",
"empty_column.home.public_timeline": "la timeline pubblica",
"empty_column.home": "Non stai ancora seguendo nessuno. Visita {public} o usa la ricerca per incontrare nuove persone.",
"empty_column.notifications": "Non hai ancora nessuna notifica. Interagisci con altri per iniziare conversazioni.",
"empty_column.public": "Qui non c'è nulla! Scrivi qualcosa pubblicamente, o aggiungi utenti da altri server per riempire questo spazio.",
"follow_request.authorize": "Autorizza",
"follow_request.reject": "Rifiuta",
"getting_started.apps": "Sono disponibili diverse app",
"getting_started.heading": "Come iniziare",
"getting_started.open_source_notice": "Mastodon è un software open source. Puoi contribuire o segnalare errori su GitHub all'indirizzo {github}. {apps}.",
"home.column_settings.advanced": "Avanzato",
"home.column_settings.basic": "Semplice",
"home.column_settings.filter_regex": "Filtra con espressioni regolari",
"home.column_settings.show_reblogs": "Mostra post condivisi",
"home.column_settings.show_replies": "Mostra risposte",
"home.settings": "Impostazioni colonna",
"lightbox.close": "Chiudi",
"loading_indicator.label": "Carico...",
"media_gallery.toggle_visible": "Imposta visibilità",
"missing_indicator.label": "Non trovato",
"navigation_bar.blocks": "Utenti bloccati",
"navigation_bar.community_timeline": "Timeline locale",
"navigation_bar.edit_profile": "Modifica profilo",
"navigation_bar.favourites": "Apprezzati",
"navigation_bar.follow_requests": "Richieste di amicizia",
"navigation_bar.info": "Informazioni estese",
"navigation_bar.logout": "Logout",
"navigation_bar.mutes": "Utenti silenziati",
"navigation_bar.preferences": "Impostazioni",
"navigation_bar.public_timeline": "Timeline federata",
"notification.favourite": "{name} ha apprezzato il tuo post",
"notification.follow": "{name} ha iniziato a seguirti",
"notification.mention": "{name} ti ha menzionato",
"notification.reblog": "{name} ha condiviso il tuo post",
"notifications.clear_confirmation": "Vuoi davvero cancellare tutte le notifiche?",
"notifications.clear": "Cancella notifiche",
"notifications.column_settings.alert": "Notifiche desktop",
"notifications.column_settings.favourite": "Apprezzati:",
"notifications.column_settings.follow": "Nuovi seguaci:",
"notifications.column_settings.mention": "Menzioni:",
"notifications.column_settings.reblog": "Post condivisi:",
"notifications.column_settings.show": "Mostra in colonna",
"notifications.column_settings.sound": "Riproduci suono",
"notifications.settings": "Impostazioni colonna",
"privacy.change": "Modifica privacy post",
"privacy.direct.long": "Invia solo a utenti menzionati",
"privacy.direct.short": "Diretto",
"privacy.private.long": "Invia solo ai seguaci",
"privacy.private.short": "Privato",
"privacy.public.long": "Invia alla timeline pubblica",
"privacy.public.short": "Pubblico",
"privacy.unlisted.long": "Non mostrare sulla timeline pubblica",
"privacy.unlisted.short": "Non elencato",
"reply_indicator.cancel": "Annulla",
"report.heading": "Nuova segnalazione",
"report.placeholder": "Commenti aggiuntivi",
"report.submit": "Invia",
"report.target": "Invio la segnalazione",
"search_results.total": "{count} {count, plural, one {risultato} other {risultati}}",
"search.placeholder": "Cerca",
"search.status_by": "Status per {name}",
"status.delete": "Elimina",
"status.favourite": "Apprezzato",
"status.load_more": "Mostra di più",
"status.media_hidden": "Allegato nascosto",
"status.mention": "Nomina @{name}",
"status.open": "Espandi questo post",
"status.reblog": "Condividi",
"status.reblogged_by": "{name} ha condiviso",
"status.reply": "Rispondi",
"status.report": "Segnala @{name}",
"status.sensitive_toggle": "Clicca per vedere",
"status.sensitive_warning": "Materiale sensibile",
"status.show_less": "Mostra meno",
"status.show_more": "Mostra di più",
"tabs_bar.compose": "Scrivi",
"tabs_bar.federated_timeline": "Federazione",
"tabs_bar.home": "Home",
"tabs_bar.local_timeline": "Locale",
"tabs_bar.notifications": "Notifiche",
"upload_area.title": "Trascina per caricare",
"upload_button.label": "Aggiungi file multimediale",
"upload_form.undo": "Annulla",
"upload_progress.label": "Sto caricando...",
"video_player.toggle_sound": "Attiva suono",
"video_player.toggle_visible": "Attiva visibilità",
"video_player.expand": "Espandi video",
"video_player.video_error": "Il video non può essere riprodotto",
};
export default it;

View File

@@ -110,7 +110,7 @@ const ja = {
"report.target": "問題のユーザー",
"search.placeholder": "検索",
"search.status_by": "{name}からの投稿",
"search_results.total": "{count, number} 件の結果",
"search_results.total": "{count} 件",
"status.delete": "削除",
"status.favourite": "お気に入り",
"status.load_more": "もっと見る",

View File

@@ -11,32 +11,28 @@ const nl = {
"status.sensitive_warning": "Gevoelige inhoud",
"status.sensitive_toggle": "Klik om te zien",
"video_player.toggle_sound": "Geluid in-/uitschakelen",
"account.mention": "Vermeld @{name}",
"account.mention": "@{name} vermelden",
"account.edit_profile": "Profiel bewerken",
"account.unblock": "Deblokkeer @{name}",
"account.unblock": "@{name} deblokkeren",
"account.unfollow": "Ontvolgen",
"account.block": "Blokkeer @{name}",
"account.block": "@{name} blokkeren",
"account.follow": "Volgen",
"account.posts": "Berichten",
"account.follows": "Volgt",
"account.followers": "Volgers",
"account.follows_you": "Volgt jou",
"account.requested": "Wacht op goedkeuring",
"account.mute": "Negeer @{name}",
"account.unmute": "Negeer @{name} niet meer",
"account.report": "Rapporteer @{name}",
"account.mute": "@{name} negeren",
"account.unmute": "@{name} niet meer negeren",
"account.report": "Report @{name}",
"getting_started.heading": "Beginnen",
"getting_started.about_addressing": "Je kunt mensen volgen als je hun gebruikersnaam en het domein van hun server kent. Voer hiervoor het e-mailachtige adres in het zoekveld in.",
"getting_started.about_shortcuts": "Als de gezochte gebruiker op hetzelfde domein zit als jijzelf, is invoeren van de gebruikersnaam genoeg. Dat geldt ook als je mensen in toots wilt vermelden.",
"getting_started.open_source_notice": "Mastodon is open-sourcesoftware. Je kunt bijdragen of problemen melden op GitHub via {github}. {apps}.",
"getting_started.apps": "Er zijn meerdere apps beschikbaar",
"column.home": "Jouw tijdlijn",
"column.community": "Lokale tijdlijn",
"column.public": "Globale tijdlijn",
"column.notifications": "Meldingen",
"column.favourites": "Favorieten",
"column.blocks": "Geblokkeerde gebruikers",
"column.mutes": "Genegeerde gebruikers",
"tabs_bar.compose": "Schrijven",
"tabs_bar.home": "Jouw tijdlijn",
"tabs_bar.mentions": "Vermeldingen",
@@ -48,7 +44,7 @@ const nl = {
"compose_form.spoiler": "Tekst achter waarschuwing verbergen",
"compose_form.spoiler_placeholder": "Waarschuwingstekst",
"compose_form.private": "Als privé markeren",
"compose_form.privacy_disclaimer": "Jouw privétoot wordt afgeleverd aan de vermelde gebruikers op {domains}. Vertrouw jij {domainsCount, plural, one {die server} other {die servers}}? Het privé plaatsen van toots werkt alleen op Mastodon-servers. Wanneer {domains} {domainsCount, plural, one {geen Mastodon-server is} other {geen Mastodon-servers zijn}}, dan wordt er niet aangegeven dat de toot privé is, waardoor het kan worden geboost of op een andere manier zichtbaar wordt gemaakt voor mensen waarvoor het niet was bedoeld.",
"compose_form.privacy_disclaimer": "Jouw privétoot wordt afgeleverd aan de vermelde gebruikers op {domains}. Vertrouw jij {domainsCount, plural, one {that server} andere {those servers}}? Het privé plaatsen van toots werkt alleen op Mastodon-servers. Als {domains} {domainsCount, plural, een {is not a Mastodon instance} andere {are not Mastodon instances}}, dan wordt er niet aangegeven dat de toot besloten is, waardoor het kan worden geboost of op een andere manier zichtbaar wordt gemaakt voor mensen waarvoor het niet was bedoeld.",
"compose_form.unlisted": "Niet op openbare tijdlijnen tonen",
"navigation_bar.edit_profile": "Profiel bewerken",
"navigation_bar.preferences": "Voorkeuren",
@@ -59,12 +55,11 @@ const nl = {
"navigation_bar.blocks": "Geblokkeerde gebruikers",
"navigation_bar.mutes": "Genegeerde gebruikers",
"navigation_bar.logout": "Afmelden",
"navigation_bar.favourites": "Favorieten",
"reply_indicator.cancel": "Annuleren",
"search.placeholder": "Zoeken",
"search.account": "Account",
"search.hashtag": "Hashtag",
"search_results.total": "{count, number} {count, plural, one {resultaat} other {resultaten}}",
"search_results.total": "{count} {count, plural, one {resultaat} other {resultaten}}",
"upload_button.label": "Media toevoegen",
"upload_form.undo": "Ongedaan maken",
"notification.follow": "{name} volgt jou nu",

View File

@@ -87,7 +87,7 @@ const no = {
"report.placeholder": "Tilleggskommentarer",
"report.submit": "Send inn",
"report.target": "Rapporterer",
"search_results.total": "{count, number} {count, plural, one {resultat} other {resultater}}",
"search_results.total": "{count} {count, plural, one {resultat} other {resultater}}",
"search.placeholder": "Søk",
"search.status_by": "Status fra {name}",
"status.delete": "Slett",

View File

@@ -80,7 +80,7 @@ const oc = {
"search.placeholder": "Recercar",
"search.account": "Compte",
"search.hashtag": "Mot-clau",
"search_results.total": "{count, number} {count, plural, one {resultat} other {resultats}}",
"search_results.total": "{count} {count, plural, one {resultat} other {resultats}}",
"search.status_by": "Estatuts de {name}",
"upload_button.label": "Apondre un mèdia",
"upload_form.undo": "Anullar",

View File

@@ -90,7 +90,7 @@ const pt_br = {
"report.placeholder": "Comentários adicionais",
"report.submit": "Enviar",
"report.target": "Denunciar",
"search_results.total": "{count, number} {count, plural, one {resultado} other {resultados}}",
"search_results.total": "{count} {count, plural, one {resultado} other {resultados}}",
"search.placeholder": "Pesquisar",
"search.status_by": "Post de {name}",
"status.delete": "Eliminar",

View File

@@ -90,7 +90,7 @@ const pt = {
"report.placeholder": "Comentários adicionais",
"report.submit": "Enviar",
"report.target": "Denunciar",
"search_results.total": "{count, number} {count, plural, one {resultado} other {resultados}}",
"search_results.total": "{count} {count, plural, one {resultado} other {resultados}}",
"search.placeholder": "Pesquisar",
"search.status_by": "Post de {name}",
"status.delete": "Eliminar",

View File

@@ -92,7 +92,7 @@ const ru = {
"report.target": "Жалуемся на",
"search.placeholder": "Поиск",
"search.status_by": "Статус от {name}",
"search_results.total": "{count, number} {count, plural, one {result} other {results}}",
"search_results.total": "{count} {count, plural, one {result} other {results}}",
"status.delete": "Удалить",
"status.favourite": "Нравится",
"status.load_more": "Показать еще",

View File

@@ -119,7 +119,7 @@ const zh_cn = {
"report.placeholder": "额外消息",
"report.submit": "提交",
"report.target": "Reporting",
"search_results.total": "{count, number} 项结果",
"search_results.total": "{count} 项结果",
"search.account": "用户",
"search.hashtag": "标签",
"search.placeholder": "搜索",

View File

@@ -112,7 +112,7 @@ const zh_hk = {
"report.placeholder": "額外訊息",
"report.submit": "提交",
"report.target": "Reporting",
"search_results.total": "{count, number} 項結果",
"search_results.total": "{count} 項結果",
"search.account": "用戶",
"search.hashtag": "標籤",
"search.placeholder": "搜尋",

View File

@@ -237,14 +237,13 @@
}
.accounts-grid {
clear: both;
box-shadow: 0 0 15px rgba($color8, 0.2);
background: $color5;
border-radius: 0 0 4px 4px;
padding: 20px 10px;
padding-bottom: 10px;
overflow: hidden;
display: flex;
flex-wrap: wrap;
@media screen and (max-width: 700px) {
border-radius: 0;
@@ -254,9 +253,11 @@
.account-grid-card {
box-sizing: border-box;
width: 335px;
float: left;
border: 1px solid $color2;
border-radius: 4px;
color: $color1;
height: 160px;
margin-bottom: 10px;
&:nth-child(odd) {

View File

@@ -8,7 +8,7 @@ class Account < ApplicationRecord
# Local users
has_one :user, inverse_of: :account
validates :username, presence: true, format: { with: /\A[a-z0-9_]+\z/i }, uniqueness: { scope: :domain, case_sensitive: false }, length: { maximum: 30 }, if: 'local?'
validates :username, presence: true, format: { with: /\A[a-z0-9_]+\z/i, message: 'only letters, numbers and underscores' }, uniqueness: { scope: :domain, case_sensitive: false }, length: { maximum: 30 }, if: 'local?'
validates :username, presence: true, uniqueness: { scope: :domain, case_sensitive: true }, unless: 'local?'
# Avatar upload
@@ -135,6 +135,10 @@ class Account < ApplicationRecord
!subscription_expires_at.blank?
end
def followers_domains
followers.reorder(nil).pluck('distinct accounts.domain')
end
def favourited?(status)
status.proper.favourites.where(account: self).count.positive?
end

View File

@@ -106,18 +106,13 @@ class MediaAttachment < ApplicationRecord
end
def set_type_and_extension
self.type = VIDEO_MIME_TYPES.include?(file_content_type) ? :video : :image
extension = appropriate_extension
basename = Paperclip::Interpolations.basename(file, :original)
file.instance_write :file_name, [basename, extension].delete_if(&:empty?).join('.')
end
def appropriate_extension
mime_type = MIME::Types[file.content_type]
extensions_for_mime_type = mime_type.empty? ? [] : mime_type.first.extensions
original_extension = Paperclip::Interpolations.extension(file, :original)
extensions_for_mime_type.include?(original_extension) ? original_extension : extensions_for_mime_type.first
if file.blank?
self.type = :unknown
else
self.type = VIDEO_MIME_TYPES.include?(file_content_type) ? :video : :image
extension = Paperclip::Interpolations.content_type_extension(file, :original)
basename = Paperclip::Interpolations.basename(file, :original)
file.instance_write :file_name, [basename, extension].delete_if(&:empty?).join('.')
end
end
end

View File

@@ -29,7 +29,7 @@ class Status < ApplicationRecord
validates :uri, uniqueness: true, unless: 'local?'
validates :text, presence: true, unless: 'reblog?'
validates_with StatusLengthValidator
validates :reblog, uniqueness: { scope: :account }, if: 'reblog?'
validates :reblog, uniqueness: { scope: :account, message: 'of status already exists' }, if: 'reblog?'
default_scope { order('id desc') }

View File

@@ -10,7 +10,7 @@ class FollowRemoteAccountService < BaseService
# important information from their feed
# @param [String] uri User URI in the form of username@domain
# @return [Account]
def call(uri, redirected = nil)
def call(uri)
username, domain = uri.split('@')
return Account.find_local(username) if TagManager.instance.local_domain?(domain)
@@ -24,14 +24,8 @@ class FollowRemoteAccountService < BaseService
raise Goldfinger::Error, 'Missing resource links' if data.link('http://schemas.google.com/g/2010#updates-from').nil? || data.link('salmon').nil? || data.link('http://webfinger.net/rel/profile-page').nil? || data.link('magic-public-key').nil?
# Disallow account hijacking
confirmed_username, confirmed_domain = data.subject.gsub(/\Aacct:/, '').split('@')
unless confirmed_username.casecmp(username).zero? && confirmed_domain.casecmp(domain).zero?
return call("#{confirmed_username}@#{confirmed_domain}", true) if redirected.nil?
raise Goldfinger::Error, 'Requested and returned acct URI do not match'
end
return Account.find_local(confirmed_username) if TagManager.instance.local_domain?(confirmed_domain)
confirmed_account = Account.find_remote(confirmed_username, confirmed_domain)

View File

@@ -1,7 +0,0 @@
%meta{ property: 'og:site_name', content: site_title }/
%meta{ property: 'og:title', content: [yield(:page_title).strip.presence, site_title].compact.join(' - ') }/
%meta{ property: 'og:description', content: account.note }/
%meta{ property: 'og:image', content: full_asset_url(account.avatar.url(:original)) }/
%meta{ property: 'og:image:width', content: '120' }/
%meta{ property: 'og:image:height', content: '120' }/
%meta{ property: 'twitter:card', content: 'summary' }/

View File

@@ -0,0 +1,12 @@
- content_for :page_title do
= t('accounts.people_who_follow', name: display_name(@account))
= render 'header', account: @account
.accounts-grid
- if @followers.empty?
= render 'nothing_here'
- else
= render partial: 'grid_card', collection: @followers, as: :account, cached: true
= paginate @followers

View File

@@ -0,0 +1,12 @@
- content_for :page_title do
= t('accounts.people_followed_by', name: display_name(@account))
= render 'header', account: @account
.accounts-grid
- if @following.empty?
= render 'nothing_here'
- else
= render partial: 'grid_card', collection: @following, as: :account, cached: true
= paginate @following

View File

@@ -5,8 +5,14 @@
%link{ rel: 'salmon', href: api_salmon_url(@account.id) }/
%link{ rel: 'alternate', type: 'application/atom+xml', href: account_url(@account, format: 'atom') }/
%meta{ property: 'og:site_name', content: site_title }/
%meta{ property: 'og:type', content: 'profile' }/
= render 'og', account: @account
%meta{ property: 'og:title', content: "#{@account.username} on #{site_hostname}" }/
%meta{ property: 'og:description', content: @account.note }/
%meta{ property: 'og:image', content: full_asset_url(@account.avatar.url(:original)) }/
%meta{ property: 'og:image:width', content: '120' }/
%meta{ property: 'og:image:height', content: '120' }/
%meta{ property: 'twitter:card', content: 'summary' }/
- if show_landing_strip?
= render partial: 'shared/landing_strip', locals: { account: @account }

View File

@@ -1,9 +1,6 @@
- content_for :page_title do
= t('accounts.people_who_follow', name: display_name(@account))
- content_for :header_tags do
= render 'accounts/og', account: @account
= render 'accounts/header', account: @account
= render 'accounts/follow_grid', accounts: @accounts

View File

@@ -1,9 +1,6 @@
- content_for :page_title do
= t('accounts.people_followed_by', name: display_name(@account))
- content_for :header_tags do
= render 'accounts/og', account: @account
= render 'accounts/header', account: @account
= render 'accounts/follow_grid', accounts: @accounts

View File

@@ -14,7 +14,7 @@
%title<
- if content_for?(:page_title)
= yield(:page_title)
= yield(:page_title).strip
= ' - '
= site_title

View File

@@ -8,12 +8,14 @@ class Pubsubhubbub::DistributionWorker
def perform(stream_entry_id)
stream_entry = StreamEntry.find(stream_entry_id)
return if stream_entry.hidden?
return if stream_entry.status.direct_visibility?
account = stream_entry.account
payload = AtomSerializer.render(AtomSerializer.new.feed(account, [stream_entry]))
domains = account.followers_domains
Subscription.where(account: account).active.select('id, callback_url').find_each do |subscription|
next unless domains.include?(Addressable::URI.parse(subscription.callback_url).host)
Pubsubhubbub::DeliveryWorker.perform_async(subscription.id, payload)
end
rescue ActiveRecord::RecordNotFound

View File

@@ -1,12 +0,0 @@
en:
activerecord:
errors:
models:
account:
attributes:
username:
invalid: only letters, numbers and underscores
status:
attributes:
reblog:
taken: of status already exists

View File

@@ -1,12 +0,0 @@
ja:
activerecord:
errors:
models:
account:
attributes:
username:
invalid: アルファベット・数値・アンダーバー(_)で入力してください
status:
attributes:
reblog:
taken: のブーストはすでに存在します

View File

@@ -7,11 +7,7 @@ module Paperclip
def make
num_frames = identify('-format %n :file', file: file.path).to_i
unless options[:style] == :original && num_frames > 1
tmp_file = Paperclip::TempfileFactory.new.generate(attachment.instance.file_file_name)
tmp_file << file.read
return tmp_file
end
return file unless options[:style] == :original && num_frames > 1
final_file = Paperclip::Transcoder.make(file, options, attachment)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

View File

@@ -1,27 +1,5 @@
require 'rails_helper'
RSpec.describe MediaAttachment, type: :model do
describe 'animated gif conversion' do
let(:media) { MediaAttachment.create(account: Fabricate(:account), file: attachment_fixture('avatar.gif')) }
it 'sets type to gifv' do
expect(media.type).to eq 'gifv'
end
it 'converts original file to mp4' do
expect(media.file_content_type).to eq 'video/mp4'
end
end
describe 'non-animated gif non-conversion' do
let(:media) { MediaAttachment.create(account: Fabricate(:account), file: attachment_fixture('attachment.gif')) }
it 'sets type to image' do
expect(media.type).to eq 'image'
end
it 'leaves original file as-is' do
expect(media.file_content_type).to eq 'image/gif'
end
end
end

View File

@@ -3,35 +3,10 @@ require 'rails_helper'
RSpec.describe FollowRemoteAccountService do
subject { FollowRemoteAccountService.new }
before do
stub_request(:get, "https://quitter.no/.well-known/host-meta").to_return(request_fixture('.host-meta.txt'))
stub_request(:get, "https://example.com/.well-known/host-meta").to_return(status: 404)
stub_request(:get, "https://quitter.no/.well-known/webfinger?resource=acct:gargron@quitter.no").to_return(request_fixture('webfinger.txt'))
stub_request(:get, "https://quitter.no/.well-known/webfinger?resource=acct:catsrgr8@quitter.no").to_return(status: 404)
stub_request(:get, "https://quitter.no/api/statuses/user_timeline/7477.atom").to_return(request_fixture('feed.txt'))
stub_request(:get, "https://quitter.no/avatar/7477-300-20160211190340.png").to_return(request_fixture('avatar.txt'))
end
it 'raises error if no such user can be resolved via webfinger' do
expect { subject.call('catsrgr8@quitter.no') }.to raise_error Goldfinger::Error
end
it 'raises error if the domain does not have webfinger' do
expect { subject.call('catsrgr8@example.com') }.to raise_error Goldfinger::Error
end
it 'returns an already existing remote account' do
old_account = Fabricate(:account, username: 'gargron', domain: 'quitter.no')
returned_account = subject.call('gargron@quitter.no')
expect(old_account.id).to eq returned_account.id
end
it 'returns a new remote account' do
account = subject.call('gargron@quitter.no')
expect(account.username).to eq 'gargron'
expect(account.domain).to eq 'quitter.no'
expect(account.remote_url).to eq 'https://quitter.no/api/statuses/user_timeline/7477.atom'
end
it 'returns nil if no such user can be resolved via webfinger'
it 'returns nil if the domain does not have webfinger'
it 'returns nil if remote user does not offer a hub URL'
it 'returns an already existing remote account'
it 'returns a new remote account'
it 'fills the remote account with profile information'
end