Merge branch 'stable' into develop
This commit is contained in:
commit
be8f920c29
23 changed files with 717 additions and 156 deletions
1
Gemfile
1
Gemfile
|
|
@ -18,6 +18,7 @@ gem "diaspora_federation-rails", "0.0.3"
|
||||||
|
|
||||||
gem "acts_as_api", "0.4.2"
|
gem "acts_as_api", "0.4.2"
|
||||||
gem "json", "1.8.3"
|
gem "json", "1.8.3"
|
||||||
|
gem "json-schema", "2.5.1"
|
||||||
|
|
||||||
# Authentication
|
# Authentication
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -395,6 +395,8 @@ GEM
|
||||||
multi_json (>= 1.3)
|
multi_json (>= 1.3)
|
||||||
rake
|
rake
|
||||||
json (1.8.3)
|
json (1.8.3)
|
||||||
|
json-schema (2.5.1)
|
||||||
|
addressable (~> 2.3.7)
|
||||||
jwt (1.5.0)
|
jwt (1.5.0)
|
||||||
kaminari (0.16.3)
|
kaminari (0.16.3)
|
||||||
actionpack (>= 3.0.0)
|
actionpack (>= 3.0.0)
|
||||||
|
|
@ -813,6 +815,7 @@ DEPENDENCIES
|
||||||
js_image_paths (= 0.0.2)
|
js_image_paths (= 0.0.2)
|
||||||
jshintrb (= 0.3.0)
|
jshintrb (= 0.3.0)
|
||||||
json (= 1.8.3)
|
json (= 1.8.3)
|
||||||
|
json-schema (= 2.5.1)
|
||||||
logging-rails (= 0.5.0)
|
logging-rails (= 0.5.0)
|
||||||
markerb (= 1.0.2)
|
markerb (= 1.0.2)
|
||||||
messagebus_ruby_api (= 1.0.3)
|
messagebus_ruby_api (= 1.0.3)
|
||||||
|
|
@ -897,4 +900,4 @@ DEPENDENCIES
|
||||||
will_paginate (= 3.0.7)
|
will_paginate (= 3.0.7)
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
1.10.5
|
1.10.6
|
||||||
|
|
|
||||||
|
|
@ -91,6 +91,6 @@
|
||||||
@import 'highlightjs/github';
|
@import 'highlightjs/github';
|
||||||
|
|
||||||
/* statistics */
|
/* statistics */
|
||||||
@import 'new_styles/statistics';
|
@import 'statistics';
|
||||||
|
|
||||||
@import "bootstrap3-switch";
|
@import "bootstrap3-switch";
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
.page-statistics {
|
.page-node_info.action-statistics {
|
||||||
h1{ text-align: center; }
|
h1{ text-align: center; }
|
||||||
|
|
||||||
h3{
|
h3{
|
||||||
24
app/controllers/node_info_controller.rb
Normal file
24
app/controllers/node_info_controller.rb
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
class NodeInfoController < ApplicationController
|
||||||
|
respond_to :json
|
||||||
|
respond_to :html, only: :statistics
|
||||||
|
|
||||||
|
def jrd
|
||||||
|
render json: NodeInfo.jrd(CGI.unescape(node_info_url("123.123").sub("123.123", "%{version}")))
|
||||||
|
end
|
||||||
|
|
||||||
|
def document
|
||||||
|
if NodeInfo.supported_version?(params[:version])
|
||||||
|
document = NodeInfoPresenter.new(params[:version])
|
||||||
|
render json: document, content_type: document.content_type
|
||||||
|
else
|
||||||
|
head :not_found
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def statistics
|
||||||
|
respond_to do |format|
|
||||||
|
format.json { render json: StatisticsPresenter.new }
|
||||||
|
format.all { @statistics = NodeInfoPresenter.new("1.0") }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
# Copyright (c) 2010-2011, Diaspora Inc. This file is
|
|
||||||
# licensed under the Affero General Public License version 3 or later. See
|
|
||||||
# the COPYRIGHT file.
|
|
||||||
|
|
||||||
class StatisticsController < ApplicationController
|
|
||||||
respond_to :html, :json
|
|
||||||
|
|
||||||
def statistics
|
|
||||||
@statistics = StatisticsPresenter.new
|
|
||||||
respond_to do |format|
|
|
||||||
format.json { render json: @statistics }
|
|
||||||
format.all
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
104
app/presenters/node_info_presenter.rb
Normal file
104
app/presenters/node_info_presenter.rb
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
class NodeInfoPresenter
|
||||||
|
delegate :as_json, :content_type, to: :document
|
||||||
|
|
||||||
|
def initialize(version)
|
||||||
|
@version = version
|
||||||
|
end
|
||||||
|
|
||||||
|
def document
|
||||||
|
@document ||= NodeInfo.build do |doc|
|
||||||
|
doc.version = @version
|
||||||
|
|
||||||
|
add_static_data doc
|
||||||
|
add_configuration doc
|
||||||
|
add_user_counts doc.usage.users
|
||||||
|
add_usage doc.usage
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_configuration(doc)
|
||||||
|
doc.software.version = version
|
||||||
|
doc.services = available_services
|
||||||
|
doc.open_registrations = open_registrations?
|
||||||
|
doc.metadata["nodeName"] = name
|
||||||
|
doc.metadata["xmppChat"] = chat_enabled?
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_static_data(doc)
|
||||||
|
doc.software.name = "diaspora"
|
||||||
|
doc.protocols.inbound << "diaspora"
|
||||||
|
doc.protocols.outbound << "diaspora"
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_user_counts(doc)
|
||||||
|
return unless expose_user_counts?
|
||||||
|
|
||||||
|
doc.total = total_users
|
||||||
|
doc.active_halfyear = halfyear_users
|
||||||
|
doc.active_month = monthly_users
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_usage(doc)
|
||||||
|
doc.local_posts = local_posts if expose_posts_counts?
|
||||||
|
doc.local_comments = local_comments if expose_comment_counts?
|
||||||
|
end
|
||||||
|
|
||||||
|
def expose_user_counts?
|
||||||
|
AppConfig.privacy.statistics.user_counts?
|
||||||
|
end
|
||||||
|
|
||||||
|
def expose_posts_counts?
|
||||||
|
AppConfig.privacy.statistics.post_counts?
|
||||||
|
end
|
||||||
|
|
||||||
|
def expose_comment_counts?
|
||||||
|
AppConfig.privacy.statistics.comment_counts?
|
||||||
|
end
|
||||||
|
|
||||||
|
def name
|
||||||
|
AppConfig.settings.pod_name
|
||||||
|
end
|
||||||
|
|
||||||
|
def version
|
||||||
|
AppConfig.version_string
|
||||||
|
end
|
||||||
|
|
||||||
|
def open_registrations?
|
||||||
|
AppConfig.settings.enable_registrations?
|
||||||
|
end
|
||||||
|
|
||||||
|
def chat_enabled?
|
||||||
|
AppConfig.chat.enabled?
|
||||||
|
end
|
||||||
|
|
||||||
|
def available_services
|
||||||
|
Configuration::KNOWN_SERVICES.select {|service|
|
||||||
|
AppConfig.show_service?(service, nil)
|
||||||
|
}.map(&:to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
def total_users
|
||||||
|
@total_users ||= User.active.count
|
||||||
|
end
|
||||||
|
|
||||||
|
def monthly_users
|
||||||
|
@monthly_users ||= User.monthly_actives.count
|
||||||
|
end
|
||||||
|
|
||||||
|
def halfyear_users
|
||||||
|
@halfyear_users ||= User.halfyear_actives.count
|
||||||
|
end
|
||||||
|
|
||||||
|
def local_posts
|
||||||
|
@local_posts ||= Post.where(type: "StatusMessage")
|
||||||
|
.joins(:author)
|
||||||
|
.where("owner_id IS NOT null")
|
||||||
|
.count
|
||||||
|
end
|
||||||
|
|
||||||
|
def local_comments
|
||||||
|
@local_comments ||= Comment.joins(:author)
|
||||||
|
.where("owner_id IS NOT null")
|
||||||
|
.count
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -2,9 +2,13 @@
|
||||||
# licensed under the Affero General Public License version 3 or later. See
|
# licensed under the Affero General Public License version 3 or later. See
|
||||||
# the COPYRIGHT file.
|
# the COPYRIGHT file.
|
||||||
|
|
||||||
class StatisticsPresenter
|
# TODO: Drop after 0.6
|
||||||
|
class StatisticsPresenter < NodeInfoPresenter
|
||||||
|
def initialize
|
||||||
|
super("1.0")
|
||||||
|
end
|
||||||
|
|
||||||
def as_json options={}
|
def as_json(_options={})
|
||||||
base_data.merge(user_counts)
|
base_data.merge(user_counts)
|
||||||
.merge(post_counts)
|
.merge(post_counts)
|
||||||
.merge(comment_counts)
|
.merge(comment_counts)
|
||||||
|
|
@ -12,91 +16,34 @@ class StatisticsPresenter
|
||||||
|
|
||||||
def base_data
|
def base_data
|
||||||
{
|
{
|
||||||
'name' => name,
|
"name" => name,
|
||||||
'network' => 'Diaspora',
|
"network" => "Diaspora",
|
||||||
'version' => version,
|
"version" => version,
|
||||||
'registrations_open' => open_registrations?,
|
"registrations_open" => open_registrations?,
|
||||||
'services' => available_services
|
"services" => available_services
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def name
|
|
||||||
AppConfig.settings.pod_name
|
|
||||||
end
|
|
||||||
|
|
||||||
def version
|
|
||||||
AppConfig.version_string
|
|
||||||
end
|
|
||||||
|
|
||||||
def open_registrations?
|
|
||||||
AppConfig.settings.enable_registrations?
|
|
||||||
end
|
|
||||||
|
|
||||||
def user_counts
|
def user_counts
|
||||||
return {} unless expose_user_counts?
|
return {} unless expose_user_counts?
|
||||||
{
|
{
|
||||||
'total_users' => total_users,
|
"total_users" => total_users,
|
||||||
'active_users_monthly' => monthly_users,
|
"active_users_monthly" => monthly_users,
|
||||||
'active_users_halfyear' => halfyear_users
|
"active_users_halfyear" => halfyear_users
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def expose_user_counts?
|
|
||||||
AppConfig.privacy.statistics.user_counts?
|
|
||||||
end
|
|
||||||
|
|
||||||
def total_users
|
|
||||||
@total_users ||= User.active.count
|
|
||||||
end
|
|
||||||
|
|
||||||
def monthly_users
|
|
||||||
@monthly_users ||= User.monthly_actives.count
|
|
||||||
end
|
|
||||||
|
|
||||||
def halfyear_users
|
|
||||||
@halfyear_users ||= User.halfyear_actives.count
|
|
||||||
end
|
|
||||||
|
|
||||||
def post_counts
|
def post_counts
|
||||||
return {} unless expose_posts_counts?
|
return {} unless expose_posts_counts?
|
||||||
{
|
{
|
||||||
'local_posts' => local_posts
|
"local_posts" => local_posts
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def local_posts
|
|
||||||
@local_posts ||= Post.where(type: "StatusMessage")
|
|
||||||
.joins(:author)
|
|
||||||
.where("owner_id IS NOT null")
|
|
||||||
.count
|
|
||||||
end
|
|
||||||
|
|
||||||
def expose_posts_counts?
|
|
||||||
AppConfig.privacy.statistics.post_counts?
|
|
||||||
end
|
|
||||||
|
|
||||||
def comment_counts
|
def comment_counts
|
||||||
return {} unless expose_comment_counts?
|
return {} unless expose_comment_counts?
|
||||||
{
|
{
|
||||||
'local_comments' => local_comments
|
"local_comments" => local_comments
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def expose_comment_counts?
|
|
||||||
AppConfig.privacy.statistics.comment_counts?
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
def local_comments
|
|
||||||
@local_comments ||= Comment.joins(:author)
|
|
||||||
.where("owner_id IS NOT null")
|
|
||||||
.count
|
|
||||||
end
|
|
||||||
|
|
||||||
def available_services
|
|
||||||
Configuration::KNOWN_SERVICES.select {|service|
|
|
||||||
AppConfig.show_service?(service, nil)
|
|
||||||
}.map(&:to_s)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
||||||
21
app/views/node_info/_statistics.haml
Normal file
21
app/views/node_info/_statistics.haml
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
-# Copyright (c) 2010-2011, Diaspora Inc. This file is
|
||||||
|
-# licensed under the Affero General Public License version 3 or later. See
|
||||||
|
-# the COPYRIGHT file.
|
||||||
|
|
||||||
|
.row
|
||||||
|
%h1= t("_statistics")
|
||||||
|
= render "statistic", name: t("statistics.name"), value: @statistics.name, activated: "serv-enabled"
|
||||||
|
= render "statistic", name: t("statistics.version"), value: @statistics.version, activated: "serv-enabled"
|
||||||
|
= render "statistic", name: t("statistics.registrations"), value: registrations_status(@statistics), activated: registrations_status_class(@statistics)
|
||||||
|
- if @statistics.expose_user_counts?
|
||||||
|
= render "statistic", name: t("statistics.total_users"), value: @statistics.total_users, activated: "serv-enabled"
|
||||||
|
= render "statistic", name: t("statistics.active_users_halfyear"), value: @statistics.halfyear_users, activated: "serv-enabled"
|
||||||
|
= render "statistic", name: t("statistics.active_users_monthly"), value: @statistics.monthly_users, activated: "serv-enabled"
|
||||||
|
- if @statistics.expose_posts_counts?
|
||||||
|
= render "statistic", name: t("statistics.local_posts"), value: @statistics.local_posts, activated: "serv-enabled"
|
||||||
|
- if @statistics.expose_comment_counts?
|
||||||
|
= render "statistic", name: t("statistics.local_comments"), value: @statistics.local_comments, activated: "serv-enabled"
|
||||||
|
.row
|
||||||
|
%h1= t("statistics.services")
|
||||||
|
- Configuration::KNOWN_SERVICES.each do |service|
|
||||||
|
= render "statistic", name: "#{service.capitalize}", value: service_status(service, @statistics.available_services), activated: service_class(service, @statistics.available_services)
|
||||||
2
app/views/node_info/statistics.html.haml
Normal file
2
app/views/node_info/statistics.html.haml
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
.container-fluid
|
||||||
|
= render "statistics"
|
||||||
1
app/views/node_info/statistics.mobile.haml
Normal file
1
app/views/node_info/statistics.mobile.haml
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
= render "statistics"
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
-# Copyright (c) 2010-2011, Diaspora Inc. This file is
|
|
||||||
-# licensed under the Affero General Public License version 3 or later. See
|
|
||||||
-# the COPYRIGHT file.
|
|
||||||
|
|
||||||
.row
|
|
||||||
%h1
|
|
||||||
= t('_statistics')
|
|
||||||
= render 'statistics/statistic', name: t('statistics.name'), value: @statistics.name, activated: "serv-enabled"
|
|
||||||
= render 'statistics/statistic', name: t('statistics.version'), value: @statistics.version, activated: "serv-enabled"
|
|
||||||
= render 'statistics/statistic', name: t('statistics.registrations'), value: registrations_status(@statistics), activated: registrations_status_class(@statistics)
|
|
||||||
- if @statistics.expose_user_counts?
|
|
||||||
= render 'statistics/statistic', name: t('statistics.total_users'), value: @statistics.total_users, activated: "serv-enabled"
|
|
||||||
= render 'statistics/statistic', name: t('statistics.active_users_halfyear'), value: @statistics.halfyear_users, activated: "serv-enabled"
|
|
||||||
= render 'statistics/statistic', name: t('statistics.active_users_monthly'), value: @statistics.monthly_users, activated: "serv-enabled"
|
|
||||||
- if @statistics.expose_posts_counts?
|
|
||||||
= render 'statistics/statistic', name: t('statistics.local_posts'), value: @statistics.local_posts, activated: "serv-enabled"
|
|
||||||
- if @statistics.expose_comment_counts?
|
|
||||||
= render 'statistics/statistic', name: t('statistics.local_comments'), value: @statistics.local_comments, activated: "serv-enabled"
|
|
||||||
.row
|
|
||||||
%h1
|
|
||||||
= t('statistics.services')
|
|
||||||
- Configuration::KNOWN_SERVICES.each do |service|
|
|
||||||
= render 'statistics/statistic', name: "#{service.capitalize}", value: service_status(service, @statistics.available_services), activated: service_class(service, @statistics.available_services)
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
.container-fluid
|
|
||||||
= render('statistics/statistics')
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
= render('statistics/statistics')
|
|
||||||
|
|
@ -26,7 +26,7 @@ AppConfig ||= Configurate::Settings.create do
|
||||||
|
|
||||||
add_provider Configurate::Provider::YAML,
|
add_provider Configurate::Provider::YAML,
|
||||||
File.join(config_dir, "diaspora.yml"),
|
File.join(config_dir, "diaspora.yml"),
|
||||||
namespace: rails_env, required: false unless rails_env == "test"
|
namespace: rails_env, required: false
|
||||||
add_provider Configurate::Provider::YAML,
|
add_provider Configurate::Provider::YAML,
|
||||||
File.join(config_dir, "diaspora.yml"),
|
File.join(config_dir, "diaspora.yml"),
|
||||||
namespace: "configuration", required: false
|
namespace: "configuration", required: false
|
||||||
|
|
|
||||||
|
|
@ -236,8 +236,10 @@ Diaspora::Application.routes.draw do
|
||||||
#Protocol Url
|
#Protocol Url
|
||||||
get 'protocol' => redirect("http://wiki.diasporafoundation.org/Federation_Protocol_Overview")
|
get 'protocol' => redirect("http://wiki.diasporafoundation.org/Federation_Protocol_Overview")
|
||||||
|
|
||||||
#Statistics
|
# NodeInfo
|
||||||
get :statistics, controller: :statistics
|
get ".well-known/nodeinfo", to: "node_info#jrd"
|
||||||
|
get "nodeinfo/:version", to: "node_info#document", as: "node_info", constraints: {version: /\d+\.\d+/}
|
||||||
|
get "statistics", to: "node_info#statistics"
|
||||||
|
|
||||||
# Terms
|
# Terms
|
||||||
if AppConfig.settings.terms.enable?
|
if AppConfig.settings.terms.enable?
|
||||||
|
|
|
||||||
147
lib/node_info.rb
Normal file
147
lib/node_info.rb
Normal file
|
|
@ -0,0 +1,147 @@
|
||||||
|
require "pathname"
|
||||||
|
require "json-schema"
|
||||||
|
|
||||||
|
module NodeInfo
|
||||||
|
VERSIONS = %w(1.0)
|
||||||
|
SCHEMAS = {}
|
||||||
|
private_constant :VERSIONS, :SCHEMAS
|
||||||
|
|
||||||
|
Document = Struct.new(:version, :software, :protocols, :services, :open_registrations, :usage, :metadata) do
|
||||||
|
Software = Struct.new(:name, :version) do
|
||||||
|
def initialize(name=nil, version=nil)
|
||||||
|
super(name, version)
|
||||||
|
end
|
||||||
|
|
||||||
|
def version_10_hash
|
||||||
|
{
|
||||||
|
"name" => name,
|
||||||
|
"version" => version
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Protocols = Struct.new(:inbound, :outbound) do
|
||||||
|
def initialize(inbound=[], outbound=[])
|
||||||
|
super(inbound, outbound)
|
||||||
|
end
|
||||||
|
|
||||||
|
def version_10_hash
|
||||||
|
{
|
||||||
|
"inbound" => inbound,
|
||||||
|
"outbound" => outbound
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Usage = Struct.new(:users, :local_posts, :local_comments) do
|
||||||
|
Users = Struct.new(:total, :active_halfyear, :active_month) do
|
||||||
|
def initialize(total=nil, active_halfyear=nil, active_month=nil)
|
||||||
|
super(total, active_halfyear, active_month)
|
||||||
|
end
|
||||||
|
|
||||||
|
def version_10_hash
|
||||||
|
{
|
||||||
|
"total" => total,
|
||||||
|
"activeHalfyear" => active_halfyear,
|
||||||
|
"activeMonth" => active_month
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(local_posts=nil, local_comments=nil)
|
||||||
|
super(Users.new, local_posts, local_comments)
|
||||||
|
end
|
||||||
|
|
||||||
|
def version_10_hash
|
||||||
|
{
|
||||||
|
"users" => users.version_10_hash,
|
||||||
|
"localPosts" => local_posts,
|
||||||
|
"localComments" => local_comments
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.build
|
||||||
|
new.tap do |doc|
|
||||||
|
yield doc
|
||||||
|
doc.validate
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(version=nil, services=[], open_registrations=nil, metadata={})
|
||||||
|
super(version, Software.new, Protocols.new, services, open_registrations, Usage.new, metadata)
|
||||||
|
end
|
||||||
|
|
||||||
|
def as_json(_options={})
|
||||||
|
case version
|
||||||
|
when "1.0"
|
||||||
|
version_10_hash
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def content_type
|
||||||
|
"application/json; profile=http://nodeinfo.diaspora.software/ns/schema/#{version}#"
|
||||||
|
end
|
||||||
|
|
||||||
|
def schema
|
||||||
|
NodeInfo.schema version
|
||||||
|
end
|
||||||
|
|
||||||
|
def validate
|
||||||
|
assert NodeInfo.supported_version?(version), "Unknown version #{version}"
|
||||||
|
JSON::Validator.validate!(schema, as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def assert(condition, message)
|
||||||
|
raise ArgumentError, message unless condition
|
||||||
|
end
|
||||||
|
|
||||||
|
def version_10_hash
|
||||||
|
deep_compact(
|
||||||
|
"version" => "1.0",
|
||||||
|
"software" => software.version_10_hash,
|
||||||
|
"protocols" => protocols.version_10_hash,
|
||||||
|
"services" => services.empty? ? nil : services,
|
||||||
|
"openRegistrations" => open_registrations,
|
||||||
|
"usage" => usage.version_10_hash,
|
||||||
|
"metadata" => metadata
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def deep_compact(hash)
|
||||||
|
hash.tap do |hash|
|
||||||
|
hash.reject! {|_, value|
|
||||||
|
deep_compact value if value.is_a? Hash
|
||||||
|
value.nil?
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.schema(version)
|
||||||
|
SCHEMAS[version] ||= JSON.parse(
|
||||||
|
Pathname.new(__dir__).join("..", "vendor", "nodeinfo", "schemas", "#{version}.json").expand_path.read
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.build(&block)
|
||||||
|
Document.build(&block)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.jrd(endpoint)
|
||||||
|
{
|
||||||
|
"links" => VERSIONS.map {|version|
|
||||||
|
{
|
||||||
|
"rel" => "http://nodeinfo.diaspora.software/ns/schema/#{version}",
|
||||||
|
"href" => endpoint % {version: version}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.supported_version?(version)
|
||||||
|
VERSIONS.include? version
|
||||||
|
end
|
||||||
|
end
|
||||||
77
spec/controllers/node_info_controller_spec.rb
Normal file
77
spec/controllers/node_info_controller_spec.rb
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
require "spec_helper"
|
||||||
|
|
||||||
|
describe NodeInfoController do
|
||||||
|
describe "#jrd" do
|
||||||
|
it "responds to JSON" do
|
||||||
|
get :jrd, format: :json
|
||||||
|
|
||||||
|
expect(response).to be_success
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a JRD" do
|
||||||
|
expect(NodeInfo).to receive(:jrd).with(include("%{version}")).and_call_original
|
||||||
|
|
||||||
|
get :jrd, format: :json
|
||||||
|
|
||||||
|
jrd = JSON.parse(response.body)
|
||||||
|
expect(jrd).to include "links" => [{
|
||||||
|
"rel" => "http://nodeinfo.diaspora.software/ns/schema/1.0",
|
||||||
|
"href" => node_info_url("1.0")
|
||||||
|
}]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#document" do
|
||||||
|
context "invalid version" do
|
||||||
|
it "responds with not found" do
|
||||||
|
get :document, version: "0.0", format: :json
|
||||||
|
|
||||||
|
expect(response.code).to eq "404"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "version 1.0" do
|
||||||
|
it "responds to JSON" do
|
||||||
|
get :document, version: "1.0", format: :json
|
||||||
|
|
||||||
|
expect(response).to be_success
|
||||||
|
end
|
||||||
|
|
||||||
|
it "calls NodeInfoPresenter" do
|
||||||
|
expect(NodeInfoPresenter).to receive(:new).with("1.0")
|
||||||
|
.and_return(double(as_json: {}, content_type: "application/json"))
|
||||||
|
|
||||||
|
get :document, version: "1.0", format: :json
|
||||||
|
end
|
||||||
|
|
||||||
|
it "notes the schema in the content type" do
|
||||||
|
get :document, version: "1.0", format: :json
|
||||||
|
|
||||||
|
expect(response.content_type).to eq "application/json; profile=http://nodeinfo.diaspora.software/ns/schema/1.0#"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#statistics" do
|
||||||
|
it "responds to format json" do
|
||||||
|
get :statistics, format: "json"
|
||||||
|
expect(response.code).to eq("200")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "contains json" do
|
||||||
|
get :statistics, format: "json"
|
||||||
|
json = JSON.parse(response.body)
|
||||||
|
expect(json["name"]).to be_present
|
||||||
|
end
|
||||||
|
|
||||||
|
it "responds to html" do
|
||||||
|
get :statistics, format: "html"
|
||||||
|
expect(response.code).to eq("200")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "responds to mobile" do
|
||||||
|
get :statistics, format: "mobile"
|
||||||
|
expect(response.code).to eq("200")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
# Copyright (c) 2010-2011, Diaspora Inc. This file is
|
|
||||||
# licensed under the Affero General Public License version 3 or later. See
|
|
||||||
# the COPYRIGHT file.
|
|
||||||
|
|
||||||
require "spec_helper"
|
|
||||||
|
|
||||||
describe StatisticsController, type: :controller do
|
|
||||||
describe "#statistics" do
|
|
||||||
it "responds to format json" do
|
|
||||||
get :statistics, format: "json"
|
|
||||||
expect(response.code).to eq("200")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "contains json" do
|
|
||||||
get :statistics, format: "json"
|
|
||||||
json = JSON.parse(response.body)
|
|
||||||
expect(json["name"]).to be_present
|
|
||||||
end
|
|
||||||
|
|
||||||
it "responds to html" do
|
|
||||||
get :statistics, format: "html"
|
|
||||||
expect(response.code).to eq("200")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "responds to mobile" do
|
|
||||||
get :statistics, format: "mobile"
|
|
||||||
expect(response.code).to eq("200")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
131
spec/presenters/node_info_presenter_spec.rb
Normal file
131
spec/presenters/node_info_presenter_spec.rb
Normal file
|
|
@ -0,0 +1,131 @@
|
||||||
|
require "spec_helper"
|
||||||
|
|
||||||
|
describe NodeInfoPresenter do
|
||||||
|
let(:presenter) { NodeInfoPresenter.new("1.0") }
|
||||||
|
let(:hash) { presenter.as_json.as_json }
|
||||||
|
|
||||||
|
describe "#as_json" do
|
||||||
|
it "works" do
|
||||||
|
expect(hash).to be_present
|
||||||
|
expect(presenter.to_json).to be_a String
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "node info contents" do
|
||||||
|
before do
|
||||||
|
AppConfig.privacy.statistics.user_counts = false
|
||||||
|
AppConfig.privacy.statistics.post_counts = false
|
||||||
|
AppConfig.privacy.statistics.comment_counts = false
|
||||||
|
end
|
||||||
|
|
||||||
|
it "provides generic pod data in json" do
|
||||||
|
expect(hash).to eq(
|
||||||
|
"version" => "1.0",
|
||||||
|
"software" => {
|
||||||
|
"name" => "diaspora",
|
||||||
|
"version" => AppConfig.version_string
|
||||||
|
},
|
||||||
|
"protocols" => {
|
||||||
|
"inbound" => ["diaspora"],
|
||||||
|
"outbound" => ["diaspora"]
|
||||||
|
},
|
||||||
|
"services" => ["facebook"],
|
||||||
|
"openRegistrations" => AppConfig.settings.enable_registrations?,
|
||||||
|
"usage" => {
|
||||||
|
"users" => {}
|
||||||
|
},
|
||||||
|
"metadata" => {
|
||||||
|
"nodeName" => AppConfig.settings.pod_name,
|
||||||
|
"xmppChat" => AppConfig.chat.enabled?
|
||||||
|
}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when services are enabled" do
|
||||||
|
before do
|
||||||
|
AppConfig.services = {
|
||||||
|
"facebook" => {
|
||||||
|
"enable" => true,
|
||||||
|
"authorized" => true
|
||||||
|
},
|
||||||
|
"twitter" => {"enable" => true},
|
||||||
|
"wordpress" => {"enable" => false},
|
||||||
|
"tumblr" => {
|
||||||
|
"enable" => true,
|
||||||
|
"authorized" => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it "provides services" do
|
||||||
|
expect(hash).to include "services" => %w(twitter facebook)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when some services are set to username authorized" do
|
||||||
|
before do
|
||||||
|
AppConfig.services = {
|
||||||
|
"facebook" => {
|
||||||
|
"enable" => true,
|
||||||
|
"authorized" => "bob"
|
||||||
|
},
|
||||||
|
"twitter" => {"enable" => true},
|
||||||
|
"wordpress" => {
|
||||||
|
"enable" => true,
|
||||||
|
"authorized" => "alice"
|
||||||
|
},
|
||||||
|
"tumblr" => {
|
||||||
|
"enable" => true,
|
||||||
|
"authorized" => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it "it doesn't list those" do
|
||||||
|
expect(hash).to include "services" => ["twitter"]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when counts are enabled" do
|
||||||
|
before do
|
||||||
|
AppConfig.privacy.statistics.user_counts = true
|
||||||
|
AppConfig.privacy.statistics.post_counts = true
|
||||||
|
AppConfig.privacy.statistics.comment_counts = true
|
||||||
|
end
|
||||||
|
|
||||||
|
it "provides generic pod data and counts in json" do
|
||||||
|
expect(hash).to include(
|
||||||
|
"usage" => {
|
||||||
|
"users" => {
|
||||||
|
"total" => User.active.count,
|
||||||
|
"activeHalfyear" => User.halfyear_actives.count,
|
||||||
|
"activeMonth" => User.monthly_actives.count
|
||||||
|
},
|
||||||
|
"localPosts" => presenter.local_posts,
|
||||||
|
"localComments" => presenter.local_comments
|
||||||
|
}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when registrations are closed" do
|
||||||
|
before do
|
||||||
|
AppConfig.settings.enable_registrations = false
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should mark open_registrations to be false" do
|
||||||
|
expect(presenter.open_registrations?).to be false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when chat is enabled" do
|
||||||
|
before do
|
||||||
|
AppConfig.chat.enabled = true
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should mark the xmppChat metadata as true" do
|
||||||
|
expect(hash).to include "metadata" => include("xmppChat" => true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -108,15 +108,5 @@ describe StatisticsPresenter do
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when registrations are closed" do
|
|
||||||
before do
|
|
||||||
AppConfig.settings.enable_registrations = false
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should mark open_registrations to be false" do
|
|
||||||
expect(@presenter.open_registrations?).to be false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
182
vendor/nodeinfo/schemas/1.0.json
vendored
Normal file
182
vendor/nodeinfo/schemas/1.0.json
vendored
Normal file
|
|
@ -0,0 +1,182 @@
|
||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
|
"id": "http://nodeinfo.diaspora.software/ns/schema/1.0#",
|
||||||
|
"description": "NodeInfo schema version 1.0.",
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"version",
|
||||||
|
"software",
|
||||||
|
"protocols",
|
||||||
|
"openRegistrations",
|
||||||
|
"usage",
|
||||||
|
"metadata"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"version": {
|
||||||
|
"description": "The schema version, must be 1.0.",
|
||||||
|
"enum": [
|
||||||
|
"1.0"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"software": {
|
||||||
|
"description": "Metadata about server software in use.",
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"name",
|
||||||
|
"version"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"description": "The canonical name of this server software.",
|
||||||
|
"enum": [
|
||||||
|
"diaspora",
|
||||||
|
"friendica",
|
||||||
|
"redmatrix"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"description": "The version of this server software.",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"protocols": {
|
||||||
|
"description": "The protocols supported on this server.",
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"inbound",
|
||||||
|
"outbound"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"inbound": {
|
||||||
|
"description": "The protocols this server can receive traffic for.",
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 1,
|
||||||
|
"items": {
|
||||||
|
"enum": [
|
||||||
|
"buddycloud",
|
||||||
|
"diaspora",
|
||||||
|
"friendica",
|
||||||
|
"gnusocial",
|
||||||
|
"libertree",
|
||||||
|
"mediagoblin",
|
||||||
|
"pumpio",
|
||||||
|
"redmatrix",
|
||||||
|
"smtp",
|
||||||
|
"tent"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"outbound": {
|
||||||
|
"description": "The protocols this server can generate traffic for.",
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 1,
|
||||||
|
"items": {
|
||||||
|
"enum": [
|
||||||
|
"buddycloud",
|
||||||
|
"diaspora",
|
||||||
|
"friendica",
|
||||||
|
"gnusocial",
|
||||||
|
"libertree",
|
||||||
|
"mediagoblin",
|
||||||
|
"pumpio",
|
||||||
|
"redmatrix",
|
||||||
|
"smtp",
|
||||||
|
"tent"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"services": {
|
||||||
|
"description": "The third party sites this servers allows to publish messages to.",
|
||||||
|
"type": "array",
|
||||||
|
"minItems": 0,
|
||||||
|
"items": {
|
||||||
|
"enum": [
|
||||||
|
"appnet",
|
||||||
|
"blogger",
|
||||||
|
"buddycloud",
|
||||||
|
"diaspora",
|
||||||
|
"dreamwidth",
|
||||||
|
"drupal",
|
||||||
|
"facebook",
|
||||||
|
"friendica",
|
||||||
|
"gnusocial",
|
||||||
|
"google",
|
||||||
|
"insanejournal",
|
||||||
|
"libertree",
|
||||||
|
"linkedin",
|
||||||
|
"livejournal",
|
||||||
|
"mediagoblin",
|
||||||
|
"myspace",
|
||||||
|
"pinterest",
|
||||||
|
"posterous",
|
||||||
|
"pumpio",
|
||||||
|
"redmatrix",
|
||||||
|
"smtp",
|
||||||
|
"tent",
|
||||||
|
"tumblr",
|
||||||
|
"twitter",
|
||||||
|
"wordpress",
|
||||||
|
"xmpp"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"openRegistrations": {
|
||||||
|
"description": "Whether this server allows open self-registration.",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"usage": {
|
||||||
|
"description": "Usage statistics for this server.",
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": [
|
||||||
|
"users"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"users": {
|
||||||
|
"description": "statistics about the users of this server.",
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"total": {
|
||||||
|
"description": "The total amount of on this server registered users.",
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0
|
||||||
|
},
|
||||||
|
"activeHalfyear": {
|
||||||
|
"description": "The amount of users that signed in at least once in the last 180 days.",
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0
|
||||||
|
},
|
||||||
|
"activeMonth": {
|
||||||
|
"description": "The amount of users that signed in at least once in the last 30 days.",
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"localPosts": {
|
||||||
|
"description": "The amount of posts that were made by users that are registered on this server.",
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0
|
||||||
|
},
|
||||||
|
"localComments": {
|
||||||
|
"description": "The amount of comments that were made by users that are registered on this server.",
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"description": "Free form key value pairs for software specific values. Clients should not rely on any specific key present.",
|
||||||
|
"type": "object",
|
||||||
|
"minProperties": 0,
|
||||||
|
"additionalProperties": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue