diff --git a/Changelog.md b/Changelog.md index 830fdca2c2d5654da71b66e73eaa38ea4214d00c..79b2e2de8ab4c8aeb570d063521d3a6ed58056f3 100644 --- a/Changelog.md +++ b/Changelog.md @@ -48,6 +48,7 @@ With the port to Bootstrap 3, app/views/terms/default.haml has a new structure. * Support color themes [#6033](https://github.com/diaspora/diaspora/pull/6033) * Add mobile services and privacy settings pages [#6086](https://github.com/diaspora/diaspora/pull/6086) * Optionally make your extended profile details public [#6162](https://github.com/diaspora/diaspora/pull/6162) +* Add admin dashboard showing latest diaspora\* version [#6216](https://github.com/diaspora/diaspora/pull/6216) # 0.5.3.0 diff --git a/app/assets/javascripts/app/pages/admin_dashboard.js b/app/assets/javascripts/app/pages/admin_dashboard.js new file mode 100644 index 0000000000000000000000000000000000000000..4826c12ea6f102c5e806d52fa4f9735029d60cf5 --- /dev/null +++ b/app/assets/javascripts/app/pages/admin_dashboard.js @@ -0,0 +1,75 @@ +// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later + +app.pages.AdminDashboard = Backbone.View.extend({ + initialize: function() { + this.updatePodStatus(); + }, + + updatePodStatus: function() { + var self = this, + tagName = ""; + $.get("https://api.github.com/repos/diaspora/diaspora/releases/latest") + .done(function(data) { + // the response might be malformed + try { + /* jshint camelcase: false */ + tagName = data.tag_name; + /* jshint camelcase: true */ + if(tagName.charAt(0) !== "v") { + self.updatePodStatusFail(); + return; + } + } catch(e) { + self.updatePodStatusFail(); + return; + } + + // split version into components + self.latestVersion = tagName.slice(1).split(".").map(Number); + if(self.podUpToDate() === null) { + self.updatePodStatusFail(); + } else { + self.updatePodStatusSuccess(); + } + }) + .fail(function() { + self.updatePodStatusFail(); + }); + }, + + updatePodStatusSuccess: function() { + $("#pod-status .alert").removeClass("alert-info"); + var podStatusMessage = Diaspora.I18n.t("admins.dashboard.up_to_date"); + if(this.podUpToDate()) { + $("#pod-status .alert").addClass("alert-success"); + } else { + podStatusMessage = Diaspora.I18n.t("admins.dashboard.outdated"); + $("#pod-status .alert").addClass("alert-danger"); + } + $("#pod-status .alert") + .html("<strong>" + podStatusMessage + "</strong>") + .append(" ") + .append(Diaspora.I18n.t("admins.dashboard.compare_versions", { + latestVersion: "v" + this.latestVersion.join("."), + podVersion: "v" + gon.podVersion + })); + }, + + updatePodStatusFail: function() { + $("#pod-status .alert") + .removeClass("alert-info") + .addClass("alert-warning") + .text(Diaspora.I18n.t("admins.dashboard.error")); + }, + + podUpToDate: function() { + var podVersion = gon.podVersion.split(/\.|\-/).map(Number); + if(this.latestVersion.length < 4 || podVersion.length < 4) { return null; } + for(var i = 0; i < 4; i++) { + if(this.latestVersion[i] < podVersion[i]) { return true; } + if(this.latestVersion[i] > podVersion[i]) { return false; } + } + return true; + } +}); +// @license-end diff --git a/app/assets/javascripts/app/router.js b/app/assets/javascripts/app/router.js index db7acc146e7f2b307773ce0b2306ce12fc4a3999..6ec0618fd9bfadd99dfd803b6df91cdd2c6f7721 100644 --- a/app/assets/javascripts/app/router.js +++ b/app/assets/javascripts/app/router.js @@ -10,6 +10,7 @@ app.Router = Backbone.Router.extend({ "user/edit": "settings", "users/sign_up": "registration", "profile/edit": "settings", + "admins/dashboard": "adminDashboard", //new hotness "posts/:id": "singlePost", @@ -47,6 +48,10 @@ app.Router = Backbone.Router.extend({ app.help.render(section); }, + adminDashboard: function() { + app.page = new app.pages.AdminDashboard(); + }, + contacts: function() { app.aspect = new app.models.Aspect(gon.preloads.aspect); app.contacts = new app.collections.Contacts(app.parsePreload("contacts")); diff --git a/app/assets/stylesheets/admin.scss b/app/assets/stylesheets/admin.scss index f8caef389b89b724ad33bc3551d68eb14e740cb8..76006defc99d73e84a369f46698d66240ab3fa54 100644 --- a/app/assets/stylesheets/admin.scss +++ b/app/assets/stylesheets/admin.scss @@ -1,30 +1,6 @@ @import 'colors'; /** ADMIN STYlES **/ - -body > div.container { - margin-top: 40px; - padding-top: 1em; -} - -#admin_nav { - font-size: 1em; - border-bottom: 2px solid #777; - margin-bottom: 20px; - - ul { - display: inline; - } - - li { - font-size: 0.8em; - display: inline; - margin-right: 0.5em; - - a { color: $blue; } - } -} - /** user search **/ .users { diff --git a/app/assets/templates/header_tpl.jst.hbs b/app/assets/templates/header_tpl.jst.hbs index 6c1da318251f75fb5e8055faceac9c22508010e1..044fc4af83a3dbdfa90b38b54e45029f160856f3 100644 --- a/app/assets/templates/header_tpl.jst.hbs +++ b/app/assets/templates/header_tpl.jst.hbs @@ -92,7 +92,7 @@ <li><a href="/user/edit">{{t "header.settings"}}</a></li> <li><a href="/help">{{t "header.help"}}</a></li> {{#if current_user.admin}} - <li><a href="/admins/user_search">{{t "header.admin"}}</a></li> + <li><a href="/admins/dashboard">{{t "header.admin"}}</a></li> {{/if}} <li><a href="/users/sign_out" data-method="delete">{{t "header.log_out"}}</a></li> </ul> diff --git a/app/controllers/admins_controller.rb b/app/controllers/admins_controller.rb index cf85c018433a307900bfcf9bf4cabc7ed862d1a3..f90860ad86583a16ffa7393d1e8d14ce3dea056e 100644 --- a/app/controllers/admins_controller.rb +++ b/app/controllers/admins_controller.rb @@ -1,4 +1,9 @@ class AdminsController < Admin::AdminController + include ApplicationHelper + + def dashboard + gon.push(pod_version: pod_version) + end def user_search if params[:admins_controller_user_search] diff --git a/app/views/admins/_admin_bar.haml b/app/views/admins/_admin_bar.haml index 75145d1bed227a7667606b70424fc86356cee714..9434736ecd24c4efe572170747b06fb9a3ade15b 100644 --- a/app/views/admins/_admin_bar.haml +++ b/app/views/admins/_admin_bar.haml @@ -1,15 +1,21 @@ - - content_for :head do = stylesheet_link_tag :admin -#admin_nav - %h2 - = t('.pages') - %ul - %li= link_to t('.user_search'), user_search_path - %li= link_to t('.weekly_user_stats'), weekly_user_stats_path - %li= link_to t('.pod_stats'), pod_stats_path - %li= link_to t('.report'), report_index_path - %li= link_to t('.correlations'), correlations_path - %li= link_to t('.sidekiq_monitor'), sidekiq_path +%h2= t(".pages") + +%ul#admin_nav.nav.nav-pills.nav-stacked + %li{role: "presentation", class: current_page?(admin_dashboard_path) && "active"} + = link_to t('.dashboard'), admin_dashboard_path + %li{role: "presentation", class: current_page?(user_search_path) && "active"} + = link_to t('.user_search'), user_search_path + %li{role: "presentation", class: current_page?(weekly_user_stats_path) && "active"} + = link_to t('.weekly_user_stats'), weekly_user_stats_path + %li{role: "presentation", class: current_page?(pod_stats_path) && "active"} + = link_to t('.pod_stats'), pod_stats_path + %li{role: "presentation", class: current_page?(report_index_path) && "active"} + = link_to t('.report'), report_index_path + %li{role: "presentation", class: current_page?(correlations_path) && "active"} + = link_to t('.correlations'), correlations_path + %li{role: "presentation", class: current_page?(sidekiq_path) && "active"} + = link_to t('.sidekiq_monitor'), sidekiq_path diff --git a/app/views/admins/correlations.haml b/app/views/admins/correlations.haml index b83fd675955be8aa3e4e3cb4224809d08de0e9a6..c2d8d391f16a6f8294e47f9bbf36da33a122c27e 100644 --- a/app/views/admins/correlations.haml +++ b/app/views/admins/correlations.haml @@ -1,9 +1,8 @@ .container - %div - = render :partial => 'admins/admin_bar' - - %div.row - %div.col-md-12 + .row + .col-md-3 + = render partial: "admins/admin_bar" + .col-md-9 %h1 = t('.correlations_count') %ul diff --git a/app/views/admins/dashboard.html.haml b/app/views/admins/dashboard.html.haml new file mode 100644 index 0000000000000000000000000000000000000000..bf7fd1089d57503350a207a408b83130060083bc --- /dev/null +++ b/app/views/admins/dashboard.html.haml @@ -0,0 +1,10 @@ +.container + .row + .col-md-3 + = render partial: "admins/admin_bar" + .col-md-9 + #pod-status + %h2 + = t(".pod_status") + .alert.alert-info{role: "alert"} + = t(".fetching_diaspora_version") diff --git a/app/views/admins/stats.html.haml b/app/views/admins/stats.html.haml index f14123d57c40dec1e196f7a86d978b89be2750fc..0dc6fac66168b6610aaf141154c6a287ede382b9 100644 --- a/app/views/admins/stats.html.haml +++ b/app/views/admins/stats.html.haml @@ -1,56 +1,56 @@ .container - %div - = render :partial => 'admins/admin_bar' - - %h1 - = t('.usage_statistic') - - %div.pull-right - = form_tag('/admins/stats', :method => 'get', class: 'form-inline') do - %select{:name => 'range'} - %option{:value => 'daily', :selected => ('selected' if params[:range] == 'daily')} - = t('.daily') - %option{:value => 'week', :selected => ('selected' if params[:range] == 'week')} - = t('.week') - %option{:value => '2weeks', :selected => ('selected' if params[:range] == '2weeks')} - = t('.2weeks') - %option{:value => 'month', :selected => ('selected' if params[:range] == 'month')} - = t('.month') - - = submit_tag t('.go'), class: 'btn btn-primary' - - %h3 - != t('.display_results', :segment => @segment) - - %div.row - - [:posts, :comments, :aspect_memberships, :users].each do |name| - - model = eval("@#{name.to_s}") - - if name == :aspect_memberships - - name = t('.shares', :count => model[:yesterday]) - - if name == :posts - - name = t('.posts', :count => model[:yesterday]) - - if name == :comments - - name = t('.comments', :count => model[:yesterday]) - - if name == :users - - name = t('.users', :count => model[:yesterday]) - - .col-md-3 - %h2{:style => 'font-weight:bold;'} - = name.to_s - %h4 - = model[:day_before] - %span.percent_change{:class => (model[:change] > 0 ? "green" : "red")} - = "(#{model[:change]}%)" - - %div.row - %div.col-md-12 - %p.alert.alert-info.text-center - != t('.current_segment', :post_yest => @posts[:yesterday]/@user_count.to_f, :post_day => @posts[:day_before]/@user_count.to_f) - - %div.row - %div.col-md-12 - %h3= t('.50_most') - %ul - - @popular_tags.each do |name,count| - %li - != t('.tag_name', :name_tag => name, :count_tag => count) + .row + .col-md-3 + = render partial: "admins/admin_bar" + .col-md-9 + %h1= t('.usage_statistic') + + .pull-right + = form_tag('/admins/stats', :method => 'get', class: 'form-inline') do + %select{:name => 'range'} + %option{:value => 'daily', :selected => ('selected' if params[:range] == 'daily')} + = t('.daily') + %option{:value => 'week', :selected => ('selected' if params[:range] == 'week')} + = t('.week') + %option{:value => '2weeks', :selected => ('selected' if params[:range] == '2weeks')} + = t('.2weeks') + %option{:value => 'month', :selected => ('selected' if params[:range] == 'month')} + = t('.month') + + = submit_tag t('.go'), class: 'btn btn-primary' + + %h3 + != t('.display_results', :segment => @segment) + + .row + - [:posts, :comments, :aspect_memberships, :users].each do |name| + - model = eval("@#{name.to_s}") + - if name == :aspect_memberships + - name = t('.shares', :count => model[:yesterday]) + - if name == :posts + - name = t('.posts', :count => model[:yesterday]) + - if name == :comments + - name = t('.comments', :count => model[:yesterday]) + - if name == :users + - name = t('.users', :count => model[:yesterday]) + + .col-md-3 + %h2{:style => 'font-weight:bold;'} + = name.to_s + %h4 + = model[:day_before] + %span.percent_change{:class => (model[:change] > 0 ? "green" : "red")} + = "(#{model[:change]}%)" + + .row + .col-md-12 + %p.alert.alert-info.text-center + != t('.current_segment', :post_yest => @posts[:yesterday]/@user_count.to_f, :post_day => @posts[:day_before]/@user_count.to_f) + + .row + .col-md-12 + %h3= t('.50_most') + %ul + - @popular_tags.each do |name,count| + %li + != t('.tag_name', :name_tag => name, :count_tag => count) diff --git a/app/views/admins/user_search.html.haml b/app/views/admins/user_search.html.haml index 741eba6932a55b1aaf6299267e6fc9083787d5c5..91a516ceb964047790ad1152c4e929c53b1b9c0a 100644 --- a/app/views/admins/user_search.html.haml +++ b/app/views/admins/user_search.html.haml @@ -1,58 +1,59 @@ .container - %div - = render :partial => 'admins/admin_bar' - - %div.row - %div.user_search.col-md-8 - %h3= t('admins.admin_bar.user_search') - = form_for @search, url: {action: 'user_search'}, html: {method: :get, class: 'form-horizontal'} do |f| - %div.form-group - = f.label :username, t('username'), class: 'col-sm-2 control-label' - %div.col-sm-10 - = f.text_field :username, class: "form-control" - - %div.form-group - = f.label :email, t('email'), class: 'col-sm-2 control-label' - %div.col-sm-10 - = f.text_field :email, class: "form-control" - - %div.form-group - = f.label :guid, t('admins.user_entry.guid'), class: 'col-sm-2 control-label' - %div.col-sm-10 - = f.text_field :guid, class: "form-control" - - %div.form-group - %div.col-sm-offset-2.col-sm-10 - = f.label :under13 do - = f.check_box :under13 - = t(".under_13") - %div.form-group - %div.clearfix.col-sm-12 - = submit_tag t("admins.stats.go"), class: "btn btn-primary pull-right" - - %div.more_invites.col-md-4 - %h3= t("shared.invitations.invites") - #add-invites-section.clearfix - != t(".you_currently", count: current_user.invitation_code.count, - link: link_to(t(".add_invites"), add_invites_path(current_user.invitation_code), - class: "btn btn-link pull-right")) - - = form_tag "admin_inviter", method: :get, class: "form-horizontal" do - .form-group - %label.col-sm-4.control-label - = t(".email_to") - .col-sm-8 - = text_field_tag "identifier", nil, class: "form-control" - .form-group - .clearfix.col-md-12 - = submit_tag t("services.remote_friend.invite"), class: "btn btn-default pull-right" - - %div.row - %div.col-md-12 - %div.alert.alert-info.text-center= t('.users', :count => @users.count) - - %div.row - %div.users.col-md-12 - %ul.media-list - - @users.each do |user| - = render partial: 'user_entry', locals: { user: user } + .row + .col-md-3 + = render partial: "admins/admin_bar" + .col-md-9 + .row + .user_search.col-md-8 + %h3= t('admins.admin_bar.user_search') + = form_for @search, url: {action: 'user_search'}, html: {method: :get, class: 'form-horizontal'} do |f| + .form-group + = f.label :username, t('username'), class: 'col-sm-2 control-label' + .col-sm-10 + = f.text_field :username, class: "form-control" + + .form-group + = f.label :email, t('email'), class: 'col-sm-2 control-label' + .col-sm-10 + = f.text_field :email, class: "form-control" + + .form-group + = f.label :guid, t('admins.user_entry.guid'), class: 'col-sm-2 control-label' + .col-sm-10 + = f.text_field :guid, class: "form-control" + + .form-group + .col-sm-offset-2.col-sm-10 + = f.label :under13 do + = f.check_box :under13 + = t(".under_13") + .form-group + .clearfix.col-sm-12 + = submit_tag t("admins.stats.go"), class: "btn btn-primary pull-right" + + .more_invites.col-md-4 + %h3= t("shared.invitations.invites") + #add-invites-section.clearfix + != t(".you_currently", count: current_user.invitation_code.count, + link: link_to(t(".add_invites"), add_invites_path(current_user.invitation_code), + class: "btn btn-link pull-right")) + + = form_tag "admin_inviter", method: :get, class: "form-horizontal" do + .form-group + %label.col-sm-4.control-label + = t(".email_to") + .col-sm-8 + = text_field_tag "identifier", nil, class: "form-control" + .form-group + .clearfix.col-md-12 + = submit_tag t("services.remote_friend.invite"), class: "btn btn-default pull-right" + + .row + .col-md-12 + .alert.alert-info.text-center= t('.users', :count => @users.count) + + .row + .users.col-md-12 + %ul.media-list + - @users.each do |user| + = render partial: 'user_entry', locals: { user: user } diff --git a/app/views/admins/weekly_user_stats.haml b/app/views/admins/weekly_user_stats.haml index 901933a97c9f421f9c284b93fa6d26f1d0c995f4..fbda595833c9db1e337eda5565f67b1bdf5f7d83 100644 --- a/app/views/admins/weekly_user_stats.haml +++ b/app/views/admins/weekly_user_stats.haml @@ -1,17 +1,18 @@ .container - %div - = render :partial => 'admins/admin_bar' + .row + .col-md-3 + = render partial: "admins/admin_bar" + .col-md-9 + %h2 + = t('.current_server', date: Time.now.to_date) - %h2 - = t('.current_server', date: Time.now.to_date) + .pull-right + = form_tag('/admins/weekly_user_stats', method: 'get', class: 'form-inline') do + = select_tag(:week, options_for_select(@created_users_by_week.keys.reverse, @selected_week)) + = submit_tag t('admins.stats.go'), class: 'btn btn-primary' - %div.pull-right - = form_tag('/admins/weekly_user_stats', method: 'get', class: 'form-inline') do - = select_tag(:week, options_for_select(@created_users_by_week.keys.reverse, @selected_week)) - = submit_tag t('admins.stats.go'), class: 'btn btn-primary' - - = t('.amount_of', count: @counter) - %br - - @created_users_by_week[@selected_week].each do |m| - = link_to m, "/u/#{m}" - %br + = t('.amount_of', count: @counter) + %br + - @created_users_by_week[@selected_week].each do |m| + = link_to m, "/u/#{m}" + %br diff --git a/app/views/report/index.html.haml b/app/views/report/index.html.haml index 46ee43c0b82caea1fbdbf18c1e11f3a9fd6ec923..0b856372972ece65cf58ad544f1374886ac6f84e 100644 --- a/app/views/report/index.html.haml +++ b/app/views/report/index.html.haml @@ -1,22 +1,21 @@ .container - %div - = render :partial => 'admins/admin_bar' - - %div.row - %div.col-md-12 + .row + .col-md-3 + = render partial: "admins/admin_bar" + .col-md-9 %h1 = t('report.title') - %div#reports + #reports - @reports.each do |r| - username = User.find_by_id(r.user_id).username - %div.content + .content %span.text = report_content(r.item_id, r.item_type) %span = raw t('report.reported_label', person: link_to(username, user_profile_path(username))) %span = t('report.reason_label', text: r.text) - %div.options.text-right + .options.text-right %span = button_to t('report.review_link'), report_path(r.id, :type => r.item_type), :class => "btn btn-info btn-small", @@ -26,4 +25,4 @@ :data => { :confirm => t('report.confirm_deletion') }, :class => "btn btn-danger btn-small", method: :delete - %div.clear + .clear diff --git a/config/locales/diaspora/en.yml b/config/locales/diaspora/en.yml index 4c12ce8c9375643325773601e2da4b1b8ca321b7..b21f6d21cc5cd625527974444a3de6ae3734707f 100644 --- a/config/locales/diaspora/en.yml +++ b/config/locales/diaspora/en.yml @@ -98,12 +98,16 @@ en: admins: admin_bar: pages: "Pages" + dashboard: "Dashboard" user_search: "User search" weekly_user_stats: "Weekly user stats" pod_stats: "Pod stats" report: "Reports" correlations: "Correlations" sidekiq_monitor: "Sidekiq monitor" + dashboard: + pod_status: "Pod status" + fetching_diaspora_version: "Fetching current diaspora* version..." correlations: correlations_count: "Correlations with sign-in count:" user_search: diff --git a/config/locales/javascript/javascript.en.yml b/config/locales/javascript/javascript.en.yml index f6755516f369354471f30f08236014292e73cf21..b6a682692bdabbb89754d24feb04e6412bb54cf1 100644 --- a/config/locales/javascript/javascript.en.yml +++ b/config/locales/javascript/javascript.en.yml @@ -29,6 +29,13 @@ en: edit: "Edit" no_results: "No results found" + admins: + dashboard: + up_to_date: "Your pod is up to date!" + outdated: "Your pod is outdated." + compare_versions: "The latest diaspora* release is <%= latestVersion %>, your pod is running <%= podVersion %>." + error: "Error fetching the latest diaspora* version." + aspects: make_aspect_list_visible: "Make contacts in this aspect visible to each other?" name: "Name" diff --git a/config/routes.rb b/config/routes.rb index c0fd79d2b489852efd75bada72f4e2b26f568464..01bfae30a11b8ea0dd3f19a0a35330115fbdd06b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -141,13 +141,14 @@ Diaspora::Application.routes.draw do # Admin backend routes - scope 'admins', :controller => :admins do + scope "admins", controller: :admins do match :user_search, via: [:get, :post] - get :admin_inviter - get :weekly_user_stats - get :correlations - get :stats, :as => 'pod_stats' - get "add_invites/:invite_code_id" => 'admins#add_invites', :as => 'add_invites' + get :admin_inviter + get :weekly_user_stats + get :correlations + get :stats, as: "pod_stats" + get :dashboard, as: "admin_dashboard" + get "add_invites/:invite_code_id" => "admins#add_invites", :as => "add_invites" end namespace :admin do diff --git a/spec/controllers/jasmine_fixtures/admins_spec.rb b/spec/controllers/jasmine_fixtures/admins_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..73086e9a3343ba4b0b33852fdb411b105384c2ed --- /dev/null +++ b/spec/controllers/jasmine_fixtures/admins_spec.rb @@ -0,0 +1,18 @@ +require "spec_helper" + +describe AdminsController, type: :controller do + describe "#dashboard" do + before do + @user = FactoryGirl.create :user + Role.add_admin(@user.person) + sign_in :user, @user + end + + context "jasmine fixtures" do + it "generates a jasmine fixture", fixture: true do + get :dashboard + save_fixture(html_for("body"), "admin_dashboard") + end + end + end +end diff --git a/spec/javascripts/app/pages/admin_dashboard_spec.js b/spec/javascripts/app/pages/admin_dashboard_spec.js new file mode 100644 index 0000000000000000000000000000000000000000..29ba0b733fa05b0a07d1fd31905f838a4daa5d14 --- /dev/null +++ b/spec/javascripts/app/pages/admin_dashboard_spec.js @@ -0,0 +1,179 @@ +describe("app.pages.AdminDashboard", function(){ + beforeEach(function() { + spec.loadFixture("admin_dashboard"); + this.view = new app.pages.AdminDashboard(); + gon.podVersion = "0.5.1.2"; + // disable jshint camelcase for i18n + /* jshint camelcase: false */ + Diaspora.I18n.load({ + admins: { + dashboard: { + up_to_date: "Your pod is up to date!", + outdated: "Your pod is outdated.", + compare_versions: "Latest d* release is <%= latestVersion%>, your pod is running <%= podVersion %>.", + error: "Error fetching the latest diaspora* version." + } + } + }); + /* jshint camelcase: true */ + }); + + describe("initialize" , function() { + it("calls updatePodStatus", function() { + spyOn(this.view, "updatePodStatus"); + this.view.initialize(); + expect(this.view.updatePodStatus).toHaveBeenCalled(); + }); + }); + + describe("updatePodStatus" , function() { + it("sends an ajax request to the github API", function() { + this.view.updatePodStatus(); + expect(jasmine.Ajax.requests.mostRecent().url).toBe( + "https://api.github.com/repos/diaspora/diaspora/releases/latest" + ); + }); + + it("calls updatePodStatusFail on a failed request", function() { + spyOn(this.view, "updatePodStatusFail"); + this.view.updatePodStatus(); + jasmine.Ajax.requests.mostRecent().respondWith({status: 400}); + expect(this.view.updatePodStatusFail).toHaveBeenCalled(); + }); + + it("calls updatePodStatusFail on a malformed response", function() { + spyOn(this.view, "updatePodStatusFail"); + spyOn(this.view, "podUpToDate").and.returnValue(true); + var responses = [ + // no object + "text", + // object without tag_name + "{\"tag\": 0}", + // tag_name not a string + "{\"tag_name\": 0}", + "{\"tag_name\": {\"id\": 0}}", + // tag_name doesn't start with "v" + "{\"tag_name\": \"0.5.1.2\"}" + ]; + + for(var i = 0; i < responses.length; i++) { + this.view.updatePodStatus(); + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 200, + responseText: responses[i] + }); + expect(this.view.updatePodStatusFail.calls.count()).toEqual(i+1); + } + }); + + it("sets latestVersion on a correct response", function() { + this.view.updatePodStatus(); + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 200, + responseText: "{\"tag_name\": \"v0.5.1.2\"}" + }); + expect(this.view.latestVersion).toEqual([0,5,1,2]); + }); + + it("calls podUpToDate on a correct response", function() { + spyOn(this.view, "podUpToDate"); + this.view.updatePodStatus(); + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 200, + responseText: "{\"tag_name\": \"v0.5.1.2\"}" + }); + expect(this.view.podUpToDate).toHaveBeenCalled(); + }); + + it("calls updatePodStatusFail if podUpToDate returns null", function() { + spyOn(this.view, "updatePodStatusFail"); + spyOn(this.view, "podUpToDate").and.returnValue(null); + this.view.updatePodStatus(); + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 200, + responseText: "{\"tag_name\": \"v0.5.1.2\"}" + }); + expect(this.view.updatePodStatusFail).toHaveBeenCalled(); + }); + + it("calls updatePodStatusSuccess if podUpToDate returns a Boolean", function() { + spyOn(this.view, "updatePodStatusSuccess"); + spyOn(this.view, "podUpToDate").and.returnValue(false); + this.view.updatePodStatus(); + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 200, + responseText: "{\"tag_name\": \"v0.5.1.2\"}" + }); + expect(this.view.updatePodStatusSuccess).toHaveBeenCalled(); + }); + }); + + describe("podUpToDate" , function() { + it("returns null if latestVersion is not long enough", function() { + this.view.latestVersion = [0, 5, 1]; + expect(this.view.podUpToDate()).toBeNull(); + }); + + it("returns true if the pod is up to date", function() { + var self = this; + [ + {latest: "0.5.1.2", pod: "0.5.1.2"}, + {latest: "0.5.1.2", pod: "0.5.1.2-abcdefg"}, + {latest: "0.5.1.2", pod: "0.5.1.2-2"}, + {latest: "0.5.1.2", pod: "0.5.1.3"}, + {latest: "0.5.1.2", pod: "0.5.2.1"}, + {latest: "0.5.1.2", pod: "0.6.0.0"}, + {latest: "0.5.1.2", pod: "2.0.0.0"} + ].forEach(function(version) { + gon.podVersion = version.pod; + self.view.latestVersion = version.latest.split(".").map(Number); + expect(self.view.podUpToDate()).toBeTruthy(); + }); + }); + + it("returns false if the pod is outdated", function() { + var self = this; + [ + {latest: "0.5.1.2", pod: "0.5.1.1"}, + {latest: "0.5.1.2", pod: "0.5.1.1-abcdefg"}, + {latest: "0.5.1.2", pod: "0.5.1.1-2"}, + {latest: "0.5.1.2", pod: "0.4.99.4"}, + {latest: "2.0.3.5", pod: "1.99.2.1"} + ].forEach(function(version) { + gon.podVersion = version.pod; + self.view.latestVersion = version.latest.split(".").map(Number); + expect(self.view.podUpToDate()).toBeFalsy(); + }); + }); + }); + + describe("updatePodStatusSuccess", function() { + it("adds a 'success' alert if the pod is up to date", function() { + spyOn(this.view, "podUpToDate").and.returnValue(true); + this.view.latestVersion = [0, 5, 1, 1]; + this.view.updatePodStatusSuccess(); + expect($("#pod-status .alert")).toHaveClass("alert-success"); + expect($("#pod-status .alert").text()).toContain("up to date"); + expect($("#pod-status .alert").text()).toContain("release is v0.5.1.1"); + expect($("#pod-status .alert").text()).toContain("pod is running v0.5.1.2"); + }); + + it("adds a 'danger' alert if the pod is up to date", function() { + spyOn(this.view, "podUpToDate").and.returnValue(false); + this.view.latestVersion = [0, 5, 1, 3]; + this.view.updatePodStatusSuccess(); + expect($("#pod-status .alert")).toHaveClass("alert-danger"); + expect($("#pod-status .alert").text()).toContain("outdated"); + expect($("#pod-status .alert").text()).toContain("release is v0.5.1.3"); + expect($("#pod-status .alert").text()).toContain("pod is running v0.5.1.2"); + }); + }); + + describe("updatePodStatusFail", function() { + it("adds a 'warning' alert", function() { + this.view.updatePodStatusFail(); + expect($("#pod-status .alert")).toHaveClass("alert-warning"); + expect($("#pod-status .alert").text()).toContain("Error"); + }); + }); +});