about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEugen Rochko <eugen@zeonfederated.com>2017-09-01 13:35:23 +0200
committerGitHub <noreply@github.com>2017-09-01 13:35:23 +0200
commit74437c6bff8d704fbb5664fe7f1b5e78e16ad086 (patch)
tree4f1720d617240d339bbfd781b53fe098190eaa8f
parent504737e860a13f9636fc47131ff27238236e8971 (diff)
Refactor Web::PushSubscription, remove welcome message (#4524)
* Refactor Web::PushSubscription, remove welcome message

* Add missing helper

* Use locale of the receiver on push notifications (#4519)

* Remove unused translations

* Fix dir on notifications
-rw-r--r--app/javascript/mastodon/service_worker/web_push_notifications.js26
-rw-r--r--app/models/session_activation.rb1
-rw-r--r--app/models/web/push_subscription.rb158
-rw-r--r--app/serializers/web/notification_serializer.rb168
-rw-r--r--config/locales/ca.yml76
-rw-r--r--config/locales/en.yml3
-rw-r--r--config/locales/fa.yml3
-rw-r--r--config/locales/fr.yml3
-rw-r--r--config/locales/ja.yml3
-rw-r--r--config/locales/nl.yml3
-rw-r--r--config/locales/oc.yml3
-rw-r--r--config/locales/pl.yml5
-rw-r--r--config/locales/ru.yml3
13 files changed, 204 insertions, 251 deletions
diff --git a/app/javascript/mastodon/service_worker/web_push_notifications.js b/app/javascript/mastodon/service_worker/web_push_notifications.js
index acb85f626..f63cff335 100644
--- a/app/javascript/mastodon/service_worker/web_push_notifications.js
+++ b/app/javascript/mastodon/service_worker/web_push_notifications.js
@@ -31,8 +31,8 @@ const notify = options =>
       const group = cloneNotification(notifications[0]);
 
       group.title = formatGroupTitle(group.data.message, group.data.count + 1);
-      group.body = `${options.title}\n${group.body}`;
-      group.data = { ...group.data, count: group.data.count + 1 };
+      group.body  = `${options.title}\n${group.body}`;
+      group.data  = { ...group.data, count: group.data.count + 1 };
 
       return self.registration.showNotification(group.title, group);
     }
@@ -43,18 +43,18 @@ const notify = options =>
 const handlePush = (event) => {
   const options = event.data.json();
 
-  options.body = options.data.nsfw || options.data.content;
-  options.image = options.image || undefined; // Null results in a network request (404)
+  options.body      = options.data.nsfw || options.data.content;
+  options.dir       = options.data.dir;
+  options.image     = options.image || undefined; // Null results in a network request (404)
   options.timestamp = options.timestamp && new Date(options.timestamp);
 
   const expandAction = options.data.actions.find(action => action.todo === 'expand');
 
   if (expandAction) {
-    options.actions = [expandAction];
-    options.hiddenActions = options.data.actions.filter(action => action !== expandAction);
-
+    options.actions          = [expandAction];
+    options.hiddenActions    = options.data.actions.filter(action => action !== expandAction);
     options.data.hiddenImage = options.image;
-    options.image = undefined;
+    options.image            = undefined;
   } else {
     options.actions = options.data.actions;
   }
@@ -75,8 +75,8 @@ const cloneNotification = (notification) => {
 const expandNotification = (notification) => {
   const nextNotification = cloneNotification(notification);
 
-  nextNotification.body = notification.data.content;
-  nextNotification.image = notification.data.hiddenImage;
+  nextNotification.body    = notification.data.content;
+  nextNotification.image   = notification.data.hiddenImage;
   nextNotification.actions = notification.data.actions.filter(action => action.todo !== 'expand');
 
   return self.registration.showNotification(nextNotification.title, nextNotification);
@@ -105,8 +105,7 @@ const openUrl = url =>
       const webClients = clientList.filter(client => /\/web\//.test(client.url));
 
       if (webClients.length !== 0) {
-        const client = findBestClient(webClients);
-
+        const client       = findBestClient(webClients);
         const { pathname } = new URL(url);
 
         if (pathname.startsWith('/web/')) {
@@ -126,8 +125,7 @@ const openUrl = url =>
   });
 
 const removeActionFromNotification = (notification, action) => {
-  const actions = notification.actions.filter(act => act.action !== action.action);
-
+  const actions          = notification.actions.filter(act => act.action !== action.action);
   const nextNotification = cloneNotification(notification);
 
   nextNotification.actions = actions;
diff --git a/app/models/session_activation.rb b/app/models/session_activation.rb
index 7eb16af8f..c1645223b 100644
--- a/app/models/session_activation.rb
+++ b/app/models/session_activation.rb
@@ -25,6 +25,7 @@
 #
 
 class SessionActivation < ApplicationRecord
+  belongs_to :user, inverse_of: :session_activations, required: true
   belongs_to :access_token, class_name: 'Doorkeeper::AccessToken', dependent: :destroy
   belongs_to :web_push_subscription, class_name: 'Web::PushSubscription', dependent: :destroy
 
diff --git a/app/models/web/push_subscription.rb b/app/models/web/push_subscription.rb
index e76f61278..79f782114 100644
--- a/app/models/web/push_subscription.rb
+++ b/app/models/web/push_subscription.rb
@@ -13,59 +13,14 @@
 #
 
 require 'webpush'
-require_relative '../../models/setting'
 
 class Web::PushSubscription < ApplicationRecord
-  include RoutingHelper
-  include StreamEntriesHelper
-  include ActionView::Helpers::TranslationHelper
-  include ActionView::Helpers::SanitizeHelper
-
   has_one :session_activation
 
-  before_create :send_welcome_notification
-
   def push(notification)
-    name = display_name notification.from_account
-    title = title_str(name, notification)
-    body = body_str notification
-    dir = dir_str body
-    url = url_str notification
-    image = image_str notification
-    actions = actions_arr notification
-
-    access_token = actions.empty? ? nil : find_or_create_access_token(notification).token
-    nsfw = notification.target_status.nil? || notification.target_status.spoiler_text.empty? ? nil : notification.target_status.spoiler_text
-
-    # TODO: Make sure that the payload does not exceed 4KB - Webpush::PayloadTooLarge
-    Webpush.payload_send(
-      message: JSON.generate(
-        title: title,
-        dir: dir,
-        image: image,
-        badge: full_asset_url('badge.png', skip_pipeline: true),
-        tag: notification.id,
-        timestamp: notification.created_at,
-        icon: notification.from_account.avatar_static_url,
-        data: {
-          content: decoder.decode(strip_tags(body)),
-          nsfw: nsfw.nil? ? nil : decoder.decode(strip_tags(nsfw)),
-          url: url,
-          actions: actions,
-          access_token: access_token,
-          message: translate('push_notifications.group.title'), # Do not pass count, will be formatted in the ServiceWorker
-        }
-      ),
-      endpoint: endpoint,
-      p256dh: key_p256dh,
-      auth: key_auth,
-      vapid: {
-        subject: "mailto:#{Setting.site_contact_email}",
-        private_key: Rails.configuration.x.vapid_private_key,
-        public_key: Rails.configuration.x.vapid_public_key,
-      },
-      ttl: 40 * 60 * 60 # 48 hours
-    )
+    I18n.with_locale(session_activation.user.locale || I18n.default_locale) do
+      push_payload(message_from(notification), 48.hours.seconds)
+    end
   end
 
   def pushable?(notification)
@@ -73,120 +28,47 @@ class Web::PushSubscription < ApplicationRecord
   end
 
   def as_payload
-    payload = {
-      id: id,
-      endpoint: endpoint,
-    }
-
+    payload = { id: id, endpoint: endpoint }
     payload[:alerts] = data['alerts'] if data && data.key?('alerts')
-
     payload
   end
 
-  private
-
-  def title_str(name, notification)
-    case notification.type
-    when :mention then translate('push_notifications.mention.title', name: name)
-    when :follow then translate('push_notifications.follow.title', name: name)
-    when :favourite then translate('push_notifications.favourite.title', name: name)
-    when :reblog then translate('push_notifications.reblog.title', name: name)
-    end
-  end
-
-  def body_str(notification)
-    case notification.type
-    when :mention then notification.target_status.text
-    when :follow then notification.from_account.note
-    when :favourite then notification.target_status.text
-    when :reblog then notification.target_status.text
-    end
-  end
-
-  def url_str(notification)
-    case notification.type
-    when :mention then web_url("statuses/#{notification.target_status.id}")
-    when :follow then web_url("accounts/#{notification.from_account.id}")
-    when :favourite then web_url("statuses/#{notification.target_status.id}")
-    when :reblog then web_url("statuses/#{notification.target_status.id}")
-    end
+  def access_token
+    find_or_create_access_token.token
   end
 
-  def actions_arr(notification)
-    actions =
-      case notification.type
-      when :mention then [
-        {
-          title: translate('push_notifications.mention.action_favourite'),
-          icon: full_asset_url('web-push-icon_favourite.png', skip_pipeline: true),
-          todo: 'request',
-          method: 'POST',
-          action: "/api/v1/statuses/#{notification.target_status.id}/favourite",
-        },
-      ]
-      else []
-      end
-
-    should_hide = notification.type.equal?(:mention) && !notification.target_status.nil? && (notification.target_status.sensitive || !notification.target_status.spoiler_text.empty?)
-    can_boost = notification.type.equal?(:mention) && !notification.target_status.nil? && !notification.target_status.hidden?
-
-    if should_hide
-      actions.insert(0, title: translate('push_notifications.mention.action_expand'), icon: full_asset_url('web-push-icon_expand.png', skip_pipeline: true), todo: 'expand', action: 'expand')
-    end
-
-    if can_boost
-      actions << { title: translate('push_notifications.mention.action_boost'), icon: full_asset_url('web-push-icon_reblog.png', skip_pipeline: true), todo: 'request', method: 'POST', action: "/api/v1/statuses/#{notification.target_status.id}/reblog" }
-    end
-
-    actions
-  end
-
-  def image_str(notification)
-    return nil if notification.target_status.nil? || notification.target_status.media_attachments.empty?
-
-    full_asset_url(notification.target_status.media_attachments.first.file.url(:small))
-  end
+  private
 
-  def dir_str(body)
-    rtl?(body) ? 'rtl' : 'ltr'
-  end
+  def push_payload(message, ttl = 5.minutes.seconds)
+    # TODO: Make sure that the payload does not
+    # exceed 4KB - Webpush::PayloadTooLarge
 
-  def send_welcome_notification
     Webpush.payload_send(
-      message: JSON.generate(
-        title: translate('push_notifications.subscribed.title'),
-        icon: full_asset_url('android-chrome-192x192.png', skip_pipeline: true),
-        badge: full_asset_url('badge.png', skip_pipeline: true),
-        data: {
-          content: translate('push_notifications.subscribed.body'),
-          actions: [],
-          url: web_url('notifications'),
-          message: translate('push_notifications.group.title'), # Do not pass count, will be formatted in the ServiceWorker
-        }
-      ),
+      message: Oj.dump(message),
       endpoint: endpoint,
       p256dh: key_p256dh,
       auth: key_auth,
+      ttl: ttl,
       vapid: {
         subject: "mailto:#{Setting.site_contact_email}",
         private_key: Rails.configuration.x.vapid_private_key,
         public_key: Rails.configuration.x.vapid_public_key,
-      },
-      ttl: 5 * 60 # 5 minutes
+      }
     )
   end
 
-  def find_or_create_access_token(notification)
+  def message_from(notification)
+    serializable_resource = ActiveModelSerializers::SerializableResource.new(notification, serializer: Web::NotificationSerializer, scope: self, scope_name: :current_push_subscription)
+    serializable_resource.as_json
+  end
+
+  def find_or_create_access_token
     Doorkeeper::AccessToken.find_or_create_for(
       Doorkeeper::Application.find_by(superapp: true),
-      notification.account.user.id,
+      session_activation.user_id,
       Doorkeeper::OAuth::Scopes.from_string('read write follow'),
       Doorkeeper.configuration.access_token_expires_in,
       Doorkeeper.configuration.refresh_token_enabled?
     )
   end
-
-  def decoder
-    @decoder ||= HTMLEntities.new
-  end
 end
diff --git a/app/serializers/web/notification_serializer.rb b/app/serializers/web/notification_serializer.rb
new file mode 100644
index 000000000..0fe75f3a8
--- /dev/null
+++ b/app/serializers/web/notification_serializer.rb
@@ -0,0 +1,168 @@
+# frozen_string_literal: true
+
+class Web::NotificationSerializer < ActiveModel::Serializer
+  include StreamEntriesHelper
+
+  class DataSerializer < ActiveModel::Serializer
+    include RoutingHelper
+    include StreamEntriesHelper
+    include ActionView::Helpers::SanitizeHelper
+
+    attributes :content, :nsfw, :url, :actions,
+               :access_token, :message
+
+    def content
+      decoder.decode(strip_tags(body))
+    end
+
+    def dir
+      rtl?(body) ? 'rtl' : 'ltr'
+    end
+
+    def nsfw
+      return if object.target_status.nil?
+      object.target_status.spoiler_text.presence
+    end
+
+    def url
+      case object.type
+      when :mention
+        web_url("statuses/#{object.target_status.id}")
+      when :follow
+        web_url("accounts/#{object.from_account.id}")
+      when :favourite
+        web_url("statuses/#{object.target_status.id}")
+      when :reblog
+        web_url("statuses/#{object.target_status.id}")
+      end
+    end
+
+    def actions
+      return @actions if defined?(@actions)
+
+      @actions = []
+
+      if object.type == :mention
+        @actions << expand_action if collapsed?
+        @actions << favourite_action
+        @actions << reblog_action if rebloggable?
+      end
+
+      @actions
+    end
+
+    def access_token
+      return if actions.empty?
+      current_push_subscription.access_token
+    end
+
+    def message
+      I18n.t('push_notifications.group.title')
+    end
+
+    private
+
+    def body
+      case object.type
+      when :mention
+        object.target_status.text
+      when :follow
+        object.from_account.note
+      when :favourite
+        object.target_status.text
+      when :reblog
+        object.target_status.text
+      end
+    end
+
+    def decoder
+      @decoder ||= HTMLEntities.new
+    end
+
+    def expand_action
+      {
+        title: I18n.t('push_notifications.mention.action_expand'),
+        icon: full_asset_url('web-push-icon_expand.png', skip_pipeline: true),
+        todo: 'expand',
+        action: 'expand',
+      }
+    end
+
+    def favourite_action
+      {
+        title: I18n.t('push_notifications.mention.action_favourite'),
+        icon: full_asset_url('web-push-icon_favourite.png', skip_pipeline: true),
+        todo: 'request',
+        method: 'POST',
+        action: "/api/v1/statuses/#{object.target_status.id}/favourite",
+      }
+    end
+
+    def reblog_action
+      {
+        title: I18n.t('push_notifications.mention.action_boost'),
+        icon: full_asset_url('web-push-icon_reblog.png', skip_pipeline: true),
+        todo: 'request',
+        method: 'POST',
+        action: "/api/v1/statuses/#{object.target_status.id}/reblog",
+      }
+    end
+
+    def collapsed?
+      !object.target_status.nil? && (object.target_status.sensitive? || object.target_status.spoiler_text.present?)
+    end
+
+    def rebloggable?
+      !object.target_status.nil? && !object.target_status.hidden?
+    end
+  end
+
+  attributes :title, :dir, :image, :badge, :tag,
+             :timestamp, :icon
+
+  has_one :data
+
+  def title
+    case object.type
+    when :mention
+      I18n.t('push_notifications.mention.title', name: name)
+    when :follow
+      I18n.t('push_notifications.follow.title', name: name)
+    when :favourite
+      I18n.t('push_notifications.favourite.title', name: name)
+    when :reblog
+      I18n.t('push_notifications.reblog.title', name: name)
+    end
+  end
+
+  def image
+    return if object.target_status.nil? || object.target_status.media_attachments.empty?
+    full_asset_url(object.target_status.media_attachments.first.file.url(:small))
+  end
+
+  def badge
+    full_asset_url('badge.png', skip_pipeline: true)
+  end
+
+  def tag
+    object.id
+  end
+
+  def timestamp
+    object.created_at
+  end
+
+  def icon
+    object.from_account.avatar_static_url
+  end
+
+  def data
+    object
+  end
+
+  private
+
+  def name
+    display_name(object.from_account)
+  end
+end
diff --git a/config/locales/ca.yml b/config/locales/ca.yml
index 58d7a6638..089d6dfa6 100644
--- a/config/locales/ca.yml
+++ b/config/locales/ca.yml
@@ -21,7 +21,7 @@ ca:
       real_conversation_body: Amb 500 caràcters a la teva disposició i suport per a continguts granulars i avisos multimèdia, pots expressar-te de la manera que vulguis.
       real_conversation_title: Construït per a converses reals
       within_reach_body: Diverses aplicacions per a iOS, Android i altres plataformes gràcies a un ecosistema API amable amb el desenvolupador, et permet mantenir-te al dia amb els teus amics en qualsevol lloc..
-      within_reach_title: Sempre a l'abast   
+      within_reach_title: Sempre a l'abast
     find_another_instance: Troba altres instàncies
     generic_description: "%{domain} és un servidor a la xarxa"
     hosted_on: Mastodon allotjat a %{domain}
@@ -215,7 +215,7 @@ ca:
       body: "%{reporter} ha informat de %{target}"
       subject: Nou informe per a %{instance} (#%{id})
   application_mailer:
-    salutation: '%{name},'
+    salutation: "%{name},"
     settings: 'Canviar preferències de correu: %{link}'
     signature: Notificacions de Mastodon desde %{instance}
     view: 'Vista:'
@@ -358,9 +358,6 @@ ca:
       title: "%{name} t'ha mencionat"
     reblog:
       title: "%{name} t'ha retootejat"
-    subscribed:
-      body: Ara pots rebre notificacions push.
-      title: Subscripció registrada
   remote_follow:
     acct: Escriu el usuari@domini de la persona que vols seguir
     missing_resource: No s'ha pogut trobar la URL de redirecció necessaria per el compte.
@@ -432,74 +429,7 @@ ca:
     reblogged: retooteado
     sensitive_content: Contingut sensible
   terms:
-    body_html: |
-      <h2>Política de privacitat</h2>
-
-      <h3 id="collect">Quina informació recollim?</h3>
-
-      <p>Recopilem informació teva quan et registres en aquesta instància i recopilem dades quan participes en el fòrum llegint, escrivint i avaluant el contingut aquí compartit.</p>
-
-      <p>En registrar-te en aquesta instància, se't pot demanar que introduexisu el teu nom i l'adreça de correu electrònic. També pots visitar el nostre lloc sense registrar-te. La teva adreça de correu electrònic es verificarà mitjançant un correu electrònic que conté un enllaç únic. Si es visita aquest enllaç, sabem que controles l'adreça de correu electrònic.</p>
-
-      <p>Quan es registra i publica, registrem l'adreça IP de la qual es va originar la publicació. També podrem conservar els registres del servidor que inclouen l'adreça IP de cada sol·licitud al nostre servidor.</p>
-
-      <h3 id="use">Per a què utilitzem la teva informació?</h3>
-
-      <p>Qualsevol de la informació que recopilem de tu pot utilitzar-se d'una de les maneres següents:</p>
-
-      <ul>
-        <li>Per a personalitzar la teva experiència &mdash; la teva informació ens ajuda a respondre millor a les teves necessitats individuals.</li>
-        <li>Per millorar el nostre lloc &mdash; ens esforcem contínuament per millorar les nostres ofertes de llocs basats en la informació i els comentaris que rebem de tu.</li>
-        <li>Per millorar el servei al client &mdash; la teva informació ens ajuda a respondre més eficaçment a les teves sol·licituds de servei al client i a les necessitats de suport.</li>
-        <li>Per enviar correus electrònics periòdics &mdash; l'adreça electrònica que proporcionis es pot utilitzar per enviar-te informació, notificacions que sol·licitis sobre canvis en temes o en resposta al teu nom d'usuari, respondre a les consultes i/o altres sol·licituds o preguntes.</li>
-      </ul>
-
-      <h3 id="protect">Com protegim la teva informació?</h3>
-
-      <p>Implementem diverses mesures de seguretat per mantenir la seguretat de la teva informació personal quan introdueixes, envies o accedeixes a la teva informació personal.</p>
-
-      <h3 id="data-retention">Quina és la nostre política de retenció de dades?</h3>
-
-      <p>Farem un esforç de bona fe per a:</p>
-
-      <ul>
-        <li>Conserva els registres de servidor que continguin l'adreça IP de totes les sol·licituds a aquest servidor no més de 90 dies.</li>
-        <li>Conserva les adreces IP associades als usuaris registrats i les seves publicacions no més de 5 anys.</li>
-      </ul>
-
-      <h3 id="cookies">Utilitzem galetes?</h3>
-
-      <p>Sí. Les cookies són fitxers petits que un lloc o el proveïdor de serveis transfereix al disc dur del vostre ordinador a través del navegador web (si ho permet). Aquestes galetes permeten al lloc reconèixer el vostre navegador i, si teniu un compte registrat, associar-lo al vostre compte registrat.</p>
-
-      <p>Utilitzem cookies per comprendre i desar les vostres preferències per a futures visites i compilar dades agregades sobre el trànsit del lloc i la interacció del lloc, de manera que podrem oferir millors experiències i eines del lloc en el futur. Podem contractar amb proveïdors de serveis de tercers per ajudar-nos a comprendre millor els visitants del nostre lloc. Aquests proveïdors de serveis no estan autoritzats a utilitzar la informació recollida en nom nostre, excepte per ajudar-nos a dur a terme i millorar el nostre negoci.</p>
-
-      <h3 id="disclose">Publiquem informació al exterior?</h3>
-
-      <p>No venem, comercialitzem ni transmetem a tercers la vostra informació d'identificació personal. Això no inclou tercers de confiança que ens ajudin a operar el nostre lloc, a dur a terme el nostre negoci o a fer-ho, sempre que aquestes parts acceptin mantenir confidencial aquesta informació. També podem publicar la vostra informació quan creiem que l'alliberament és apropiat per complir amb la llei, fer complir les polítiques del nostre lloc o protegir els nostres drets o altres drets, propietat o seguretat. No obstant això, la informació de visitant que no sigui personalment identificable es pot proporcionar a altres parts per a la comercialització, la publicitat o altres usos.</p>  
-
-      <h3 id="third-party">Vincles de tercers</h3>
-
-      <p>De tant en tant, segons el nostre criteri, podem incloure o oferir productes o serveis de tercers al nostre lloc. Aquests llocs de tercers tenen polítiques de privadesa separades i independents. Per tant, no tenim responsabilitat ni responsabilitat civil pel contingut i les activitats d'aquests llocs enllaçats. No obstant això, busquem protegir la integritat del nostre lloc i donem la benvinguda a qualsevol comentari sobre aquests llocs.</p>
-
-      <h3 id="coppa">Compliment de la Llei de protecció de la privacitat en línia dels nens</h3>
-
-      <p>El nostre lloc, productes i serveis estan dirigits a persones que tenen almenys 13 anys. Si aquest servidor es troba als EUA, i teniu menys de 13 anys, segons els requisits de COPPA (<a href="https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act">Children's Online Privacy Protection Act</a>) no feu servir aquest lloc.</p>
-
-      <h3 id="online">Només la política de privacitat en línia</h3>
-
-      <p>Aquesta política de privacitat en línia només s'aplica a la informació recopilada a través del nostre lloc i no a la informació recopilada fora de línia.</p>
-
-      <h3 id="consent">El vostre consentiment</h3>
-
-      <p>En utilitzar el nostre lloc, accepta la política de privadesa del nostre lloc web.</p>
-
-      <h3 id="changes">Canvis a la nostra política de privacitat</h3>
-
-      <p>Si decidim canviar la nostra política de privadesa, publicarem aquests canvis en aquesta pàgina.</p>
-
-      <p>Aquest document és CC-BY-SA. Es va actualitzar per última vegada el 31 de maig de 2013.</p>
-
-      <p>Originalment adaptat a la <a href="https://github.com/discourse/discourse">política de privadesa del Discurs</a>.</p>
+    body_html: "<h2>Política de privacitat</h2>\n\n<h3 id=\"collect\">Quina informació recollim?</h3>\n\n<p>Recopilem informació teva quan et registres en aquesta instància i recopilem dades quan participes en el fòrum llegint, escrivint i avaluant el contingut aquí compartit.</p>\n\n<p>En registrar-te en aquesta instància, se't pot demanar que introduexisu el teu nom i l'adreça de correu electrònic. També pots visitar el nostre lloc sense registrar-te. La teva adreça de correu electrònic es verificarà mitjançant un correu electrònic que conté un enllaç únic. Si es visita aquest enllaç, sabem que controles l'adreça de correu electrònic.</p>\n\n<p>Quan es registra i publica, registrem l'adreça IP de la qual es va originar la publicació. També podrem conservar els registres del servidor que inclouen l'adreça IP de cada sol·licitud al nostre servidor.</p>\n\n<h3 id=\"use\">Per a què utilitzem la teva informació?</h3>\n\n<p>Qualsevol de la informació que recopilem de tu pot utilitzar-se d'una de les maneres següents:</p>\n\n<ul>\n  <li>Per a personalitzar la teva experiència &mdash; la teva informació ens ajuda a respondre millor a les teves necessitats individuals.</li>\n  <li>Per millorar el nostre lloc &mdash; ens esforcem contínuament per millorar les nostres ofertes de llocs basats en la informació i els comentaris que rebem de tu.</li>\n  <li>Per millorar el servei al client &mdash; la teva informació ens ajuda a respondre més eficaçment a les teves sol·licituds de servei al client i a les necessitats de suport.</li>\n  <li>Per enviar correus electrònics periòdics &mdash; l'adreça electrònica que proporcionis es pot utilitzar per enviar-te informació, notificacions que sol·licitis sobre canvis en temes o en resposta al teu nom d'usuari, respondre a les consultes i/o altres sol·licituds o preguntes.</li>\n</ul>\n\n<h3 id=\"protect\">Com protegim la teva informació?</h3>\n\n<p>Implementem diverses mesures de seguretat per mantenir la seguretat de la teva informació personal quan introdueixes, envies o accedeixes a la teva informació personal.</p>\n\n<h3 id=\"data-retention\">Quina és la nostre política de retenció de dades?</h3>\n\n<p>Farem un esforç de bona fe per a:</p>\n\n<ul>\n  <li>Conserva els registres de servidor que continguin l'adreça IP de totes les sol·licituds a aquest servidor no més de 90 dies.</li>\n  <li>Conserva les adreces IP associades als usuaris registrats i les seves publicacions no més de 5 anys.</li>\n</ul>\n\n<h3 id=\"cookies\">Utilitzem galetes?</h3>\n\n<p>Sí. Les cookies són fitxers petits que un lloc o el proveïdor de serveis transfereix al disc dur del vostre ordinador a través del navegador web (si ho permet). Aquestes galetes permeten al lloc reconèixer el vostre navegador i, si teniu un compte registrat, associar-lo al vostre compte registrat.</p>\n\n<p>Utilitzem cookies per comprendre i desar les vostres preferències per a futures visites i compilar dades agregades sobre el trànsit del lloc i la interacció del lloc, de manera que podrem oferir millors experiències i eines del lloc en el futur. Podem contractar amb proveïdors de serveis de tercers per ajudar-nos a comprendre millor els visitants del nostre lloc. Aquests proveïdors de serveis no estan autoritzats a utilitzar la informació recollida en nom nostre, excepte per ajudar-nos a dur a terme i millorar el nostre negoci.</p>\n\n<h3 id=\"disclose\">Publiquem informació al exterior?</h3>\n\n<p>No venem, comercialitzem ni transmetem a tercers la vostra informació d'identificació personal. Això no inclou tercers de confiança que ens ajudin a operar el nostre lloc, a dur a terme el nostre negoci o a fer-ho, sempre que aquestes parts acceptin mantenir confidencial aquesta informació. També podem publicar la vostra informació quan creiem que l'alliberament és apropiat per complir amb la llei, fer complir les polítiques del nostre lloc o protegir els nostres drets o altres drets, propietat o seguretat. No obstant això, la informació de visitant que no sigui personalment identificable es pot proporcionar a altres parts per a la comercialització, la publicitat o altres usos.</p>  \n\n<h3 id=\"third-party\">Vincles de tercers</h3>\n\n<p>De tant en tant, segons el nostre criteri, podem incloure o oferir productes o serveis de tercers al nostre lloc. Aquests llocs de tercers tenen polítiques de privadesa separades i independents. Per tant, no tenim responsabilitat ni responsabilitat civil pel contingut i les activitats d'aquests llocs enllaçats. No obstant això, busquem protegir la integritat del nostre lloc i donem la benvinguda a qualsevol comentari sobre aquests llocs.</p>\n\n<h3 id=\"coppa\">Compliment de la Llei de protecció de la privacitat en línia dels nens</h3>\n\n<p>El nostre lloc, productes i serveis estan dirigits a persones que tenen almenys 13 anys. Si aquest servidor es troba als EUA, i teniu menys de 13 anys, segons els requisits de COPPA (<a href=\"https://en.wikipedia.org/wiki/Children%27s_Online_Privacy_Protection_Act\">Children's Online Privacy Protection Act</a>) no feu servir aquest lloc.</p>\n\n<h3 id=\"online\">Només la política de privacitat en línia</h3>\n\n<p>Aquesta política de privacitat en línia només s'aplica a la informació recopilada a través del nostre lloc i no a la informació recopilada fora de línia.</p>\n\n<h3 id=\"consent\">El vostre consentiment</h3>\n\n<p>En utilitzar el nostre lloc, accepta la política de privadesa del nostre lloc web.</p>\n\n<h3 id=\"changes\">Canvis a la nostra política de privacitat</h3>\n\n<p>Si decidim canviar la nostra política de privadesa, publicarem aquests canvis en aquesta pàgina.</p>\n\n<p>Aquest document és CC-BY-SA. Es va actualitzar per última vegada el 31 de maig de 2013.</p>\n\n<p>Originalment adaptat a la <a href=\"https://github.com/discourse/discourse\">política de privadesa del Discurs</a>.</p>\n"
     title: "%{instance} Condicions del servei i política de privadesa"
   time:
     formats:
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 1a9926edd..2599b6078 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -382,9 +382,6 @@ en:
       title: "%{name} mentioned you"
     reblog:
       title: "%{name} boosted your status"
-    subscribed:
-      body: You can now receive push notifications.
-      title: Subscription registered!
   remote_follow:
     acct: Enter your username@domain you want to follow from
     missing_resource: Could not find the required redirect URL for your account
diff --git a/config/locales/fa.yml b/config/locales/fa.yml
index 0c575e23e..6959134a6 100644
--- a/config/locales/fa.yml
+++ b/config/locales/fa.yml
@@ -357,9 +357,6 @@ fa:
       title: "%{name} از شما نام برد"
     reblog:
       title: "%{name} نوشتهٔ شما را بازبوقید"
-    subscribed:
-      body: از این به بعد سرور می‌تواندبه شما اعلان‌های تازه بفرستد .
-      title: عضویت ثبت شد!
   remote_follow:
     acct: نشانی حساب username@domain خود را این‌جا بنویسید
     missing_resource: نشانی اینترنتی برای رسیدن به حساب شما پیدا نشد
diff --git a/config/locales/fr.yml b/config/locales/fr.yml
index a7c5bf144..6d7479cc9 100644
--- a/config/locales/fr.yml
+++ b/config/locales/fr.yml
@@ -353,9 +353,6 @@ fr:
       title: "%{name} vous a mentionné·e"
     reblog:
       title: "%{name} a partagé⋅e votre statut"
-    subscribed:
-      body: Vous pouvez désormais recevoir des notifications push.
-      title: Abonnements aux notifications push
   remote_follow:
     acct: Entrez votre pseudo@instance depuis lequel vous voulez suivre ce⋅tte utilisateur⋅rice
     missing_resource: L’URL de redirection n’a pas pu être trouvée
diff --git a/config/locales/ja.yml b/config/locales/ja.yml
index e4b18529c..4f6f92866 100644
--- a/config/locales/ja.yml
+++ b/config/locales/ja.yml
@@ -381,9 +381,6 @@ ja:
       title: "%{name} さんから返信がありました"
     reblog:
       title: あなたのトゥートが %{name} さんにブーストされました
-    subscribed:
-      body: あなたはプッシュ通知を受け取ることが出来ます
-      title: Subscription が登録されました
   remote_follow:
     acct: あなたの ユーザー名@ドメイン を入力してください
     missing_resource: リダイレクト先が見つかりませんでした
diff --git a/config/locales/nl.yml b/config/locales/nl.yml
index 6562767a9..e738d5662 100644
--- a/config/locales/nl.yml
+++ b/config/locales/nl.yml
@@ -353,9 +353,6 @@ nl:
       title: "%{name} vermeldde jou"
     reblog:
       title: "%{name} boostte jouw toot"
-    subscribed:
-      body: Je kan nu pushmeldingen ontvangen.
-      title: Aanmelding bevestigd!
   remote_follow:
     acct: Geef jouw account@domein.tld op waarvandaan je wilt volgen
     missing_resource: Kon vereiste doorverwijzings-URL voor jouw account niet vinden
diff --git a/config/locales/oc.yml b/config/locales/oc.yml
index 99c377f18..ba7993d7c 100644
--- a/config/locales/oc.yml
+++ b/config/locales/oc.yml
@@ -448,9 +448,6 @@ oc:
       title: "%{name} vos a mencionat"
     reblog:
       title: "%{name} a partejat vòstre estatut"
-    subscribed:
-      body: Podètz ara recebre las notificacions push.
-      title: Abonament enregistrat !
   remote_follow:
     acct: Picatz vòstre utilizaire@instància que cal utilizar per sègre aqueste utilizaire
     missing_resource: URL de redireccion pas trobada
diff --git a/config/locales/pl.yml b/config/locales/pl.yml
index 9f0d9bb29..2b2cbb26b 100644
--- a/config/locales/pl.yml
+++ b/config/locales/pl.yml
@@ -225,8 +225,6 @@ pl:
     signature: Powiadomienie Mastodona z instancji %{instance}
     view: 'Zobacz:'
   applications:
-    invalid_url: Ten URL jest nieprawidłowy
-  applications:
     created: Pomyślnie utworzono aplikację
     destroyed: Pomyślnie usunięto aplikację
     invalid_url: Wprowadzony adres URL jest nieprawidłowy
@@ -375,9 +373,6 @@ pl:
       title: "%{name} wspomniał o Tobie"
     reblog:
       title: "%{name} podbił Twój status"
-    subscribed:
-      body: Otrzymujesz teraz powiadomienia push.
-      title: Zarejestrowano subskrypcję!
   remote_follow:
     acct: Podaj swój adres (nazwa@domena), z którego chcesz śledzić
     missing_resource: Nie udało się znaleźć adresu przekierowania z Twojej domeny
diff --git a/config/locales/ru.yml b/config/locales/ru.yml
index 0156f0e95..5c87ebf26 100644
--- a/config/locales/ru.yml
+++ b/config/locales/ru.yml
@@ -278,9 +278,6 @@ ru:
       title: Вас упомянул(а) %{name}
     reblog:
       title: "%{name} продвинул(а) Ваш статус"
-    subscribed:
-      body: Теперь Вы можете получать push-уведомления.
-      title: Подписка зарегистрирована!
   remote_follow:
     acct: Введите username@domain, откуда Вы хотите подписаться
     missing_resource: Поиск требуемого перенаправления URL для Вашего аккаунта завершился неудачей