diff --git a/api/app/assets/javascripts/mno_enterprise/config.js.coffee.erb b/api/app/assets/javascripts/mno_enterprise/config.js.coffee.erb
index 33f2e123f..f1870a495 100644
--- a/api/app/assets/javascripts/mno_enterprise/config.js.coffee.erb
+++ b/api/app/assets/javascripts/mno_enterprise/config.js.coffee.erb
@@ -11,6 +11,7 @@ angular.module('mnoEnterprise.configuration', [])
.constant('PRICING_CONFIG', <%= Hash(Settings.pricing).to_json %>)
.constant('DOCK_CONFIG', <%= Hash(Settings.dock).to_json %>)
.constant('DEVELOPER_SECTION_CONFIG', <%= Hash(Settings.developer).to_json %>)
+ .constant('REVIEWS_CONFIG', <%= Hash(Settings.reviews).to_json %>)
.constant('GOOGLE_TAG_CONTAINER_ID', <%= MnoEnterprise.google_tag_container.to_json %>)
.constant('INTERCOM_ID', <%= MnoEnterprise.intercom_app_id.to_json %>)
.constant('APP_NAME', <%= MnoEnterprise.app_name.to_json %>)
diff --git a/api/app/controllers/mno_enterprise/jpi/v1/admin/app_reviews_controller.rb b/api/app/controllers/mno_enterprise/jpi/v1/admin/app_reviews_controller.rb
new file mode 100644
index 000000000..16b0c25b8
--- /dev/null
+++ b/api/app/controllers/mno_enterprise/jpi/v1/admin/app_reviews_controller.rb
@@ -0,0 +1,30 @@
+module MnoEnterprise
+ class Jpi::V1::Admin::AppReviewsController < Jpi::V1::Admin::BaseResourceController
+ # GET /mnoe/jpi/v1/admin/app_reviews
+ def index
+ @app_reviews = MnoEnterprise::AppReview
+ @app_reviews = @app_reviews.limit(params[:limit]) if params[:limit]
+ @app_reviews = @app_reviews.skip(params[:offset]) if params[:offset]
+ @app_reviews = @app_reviews.order_by(params[:order_by]) if params[:order_by]
+ @app_reviews = @app_reviews.where(params[:where]) if params[:where]
+ @app_reviews = @app_reviews.all.fetch
+ response.headers['X-Total-Count'] = @app_reviews.metadata[:pagination][:count]
+ end
+
+ # GET /mnoe/jpi/v1/admin/app_reviews/1
+ def show
+ @app_review = MnoEnterprise::AppReview.find(params[:id])
+ end
+
+ # PATCH /mnoe/jpi/v1/admin/app_reviews/1
+ def update
+ @app_review = MnoEnterprise::AppReview.find(params[:id])
+ @app_review.update(app_review_params)
+ render :show
+ end
+
+ def app_review_params
+ params.require(:app_review).permit(:status)
+ end
+ end
+end
diff --git a/api/app/controllers/mno_enterprise/jpi/v1/app_reviews_controller.rb b/api/app/controllers/mno_enterprise/jpi/v1/app_reviews_controller.rb
new file mode 100644
index 000000000..d4bcb6a4c
--- /dev/null
+++ b/api/app/controllers/mno_enterprise/jpi/v1/app_reviews_controller.rb
@@ -0,0 +1,34 @@
+module MnoEnterprise
+ class Jpi::V1::AppReviewsController < Jpi::V1::BaseResourceController
+ # GET /mnoe/jpi/v1/marketplace/:id/app_reviews
+ def index
+ @app_reviews = MnoEnterprise::AppReview.approved.where(reviewable_id: params[:id])
+ @app_reviews = @app_reviews.limit(params[:limit]) if params[:limit]
+ @app_reviews = @app_reviews.skip(params[:offset]) if params[:offset]
+ @app_reviews = @app_reviews.order_by(params[:order_by]) if params[:order_by]
+ @app_reviews = @app_reviews.where(params[:where]) if params[:where]
+ @app_reviews = @app_reviews.all.fetch
+ response.headers['X-Total-Count'] = @app_reviews.metadata[:pagination][:count]
+ end
+
+ # POST /mnoe/jpi/v1/marketplace/:id/app_reviews
+ def create
+ @app = MnoEnterprise::App.find(params[:id])
+ return render json: "could not find App #{params[:id]}", status: :not_found unless @app
+
+ # TODO: use the has_many associations -> @app.reviews.build
+ @app_review = MnoEnterprise::AppReview.new(review_params(@app.id))
+ if @app_review.save
+ @average_rating = @app.reload.average_rating
+ render :show
+ else
+ render json: @app_review.errors, status: :bad_request
+ end
+ end
+
+ def review_params(app_id)
+ params.require(:app_review).permit(:rating, :description, :organization_id)
+ .merge(app_id: app_id, user_id: current_user.id)
+ end
+ end
+end
diff --git a/api/app/views/mno_enterprise/jpi/v1/admin/app_reviews/_app_review.json.jbuilder b/api/app/views/mno_enterprise/jpi/v1/admin/app_reviews/_app_review.json.jbuilder
new file mode 100644
index 000000000..938895814
--- /dev/null
+++ b/api/app/views/mno_enterprise/jpi/v1/admin/app_reviews/_app_review.json.jbuilder
@@ -0,0 +1,12 @@
+json.id app_review.id
+json.rating app_review.rating
+json.description app_review.description
+json.status app_review.status
+json.app_id app_review.app_id
+json.app_name app_review.app_name
+json.user_id app_review.user_id
+json.user_name app_review.user_name
+json.organization_id app_review.organization_id
+json.organization_name app_review.organization_name
+json.created_at app_review.created_at
+json.updated_at app_review.updated_at
diff --git a/api/app/views/mno_enterprise/jpi/v1/admin/app_reviews/index.json.jbuilder b/api/app/views/mno_enterprise/jpi/v1/admin/app_reviews/index.json.jbuilder
new file mode 100644
index 000000000..29128d36f
--- /dev/null
+++ b/api/app/views/mno_enterprise/jpi/v1/admin/app_reviews/index.json.jbuilder
@@ -0,0 +1 @@
+json.app_reviews @app_reviews, partial: 'app_review', as: :app_review
diff --git a/api/app/views/mno_enterprise/jpi/v1/admin/app_reviews/show.json.jbuilder b/api/app/views/mno_enterprise/jpi/v1/admin/app_reviews/show.json.jbuilder
new file mode 100644
index 000000000..992a4dd74
--- /dev/null
+++ b/api/app/views/mno_enterprise/jpi/v1/admin/app_reviews/show.json.jbuilder
@@ -0,0 +1,3 @@
+json.app_review do
+ json.partial! 'app_review', app_review: @app_review
+end
diff --git a/api/app/views/mno_enterprise/jpi/v1/app_reviews/_resource.json.jbuilder b/api/app/views/mno_enterprise/jpi/v1/app_reviews/_resource.json.jbuilder
new file mode 100644
index 000000000..e2fbd8743
--- /dev/null
+++ b/api/app/views/mno_enterprise/jpi/v1/app_reviews/_resource.json.jbuilder
@@ -0,0 +1,12 @@
+json.id app_review[:id]
+json.rating app_review[:rating]
+json.description app_review[:description]
+json.status app_review[:status]
+json.user_id app_review[:user_id]
+json.user_name app_review[:user_name]
+json.organization_id app_review[:organization_id]
+json.organization_name app_review[:organization_name]
+json.app_id app_review[:app_id]
+json.app_name app_review[:app_name]
+json.created_at app_review[:created_at]
+json.updated_at app_review[:updated_at]
diff --git a/api/app/views/mno_enterprise/jpi/v1/app_reviews/index.json.jbuilder b/api/app/views/mno_enterprise/jpi/v1/app_reviews/index.json.jbuilder
new file mode 100644
index 000000000..7d5ec6304
--- /dev/null
+++ b/api/app/views/mno_enterprise/jpi/v1/app_reviews/index.json.jbuilder
@@ -0,0 +1,6 @@
+json.app_reviews do
+ json.array! @app_reviews do |app_review|
+ json.partial! 'resource', app_review: app_review
+ end
+end
+
diff --git a/api/app/views/mno_enterprise/jpi/v1/app_reviews/show.json.jbuilder b/api/app/views/mno_enterprise/jpi/v1/app_reviews/show.json.jbuilder
new file mode 100644
index 000000000..99a484132
--- /dev/null
+++ b/api/app/views/mno_enterprise/jpi/v1/app_reviews/show.json.jbuilder
@@ -0,0 +1,4 @@
+json.app_review do
+ json.partial! 'resource', app_review: @app_review
+end
+json.average_rating @average_rating
diff --git a/api/app/views/mno_enterprise/jpi/v1/marketplace/_app.json.jbuilder b/api/app/views/mno_enterprise/jpi/v1/marketplace/_app.json.jbuilder
index df9088a49..ebd158932 100644
--- a/api/app/views/mno_enterprise/jpi/v1/marketplace/_app.json.jbuilder
+++ b/api/app/views/mno_enterprise/jpi/v1/marketplace/_app.json.jbuilder
@@ -10,6 +10,7 @@ json.is_coming_soon app.coming_soon?
json.single_billing app.single_billing?
json.multi_instantiable app.multi_instantiable
json.subcategories app.subcategories
+json.average_rating app.average_rating
if app.logo
json.logo app.logo.to_s
diff --git a/api/app/views/mno_enterprise/jpi/v1/marketplace/index.json.jbuilder b/api/app/views/mno_enterprise/jpi/v1/marketplace/index.json.jbuilder
index 96885f97f..0d716c13e 100644
--- a/api/app/views/mno_enterprise/jpi/v1/marketplace/index.json.jbuilder
+++ b/api/app/views/mno_enterprise/jpi/v1/marketplace/index.json.jbuilder
@@ -1,4 +1,2 @@
-json.cache! ['v1', 'marketplace'], expires_in: 20.minutes do
- json.categories @categories
- json.apps @apps, partial: 'app', as: :app
-end
+json.categories @categories
+json.apps @apps, partial: 'app', as: :app
diff --git a/api/app/views/mno_enterprise/jpi/v1/marketplace/show.json.jbuilder b/api/app/views/mno_enterprise/jpi/v1/marketplace/show.json.jbuilder
index f00a81ec2..89d0bf899 100644
--- a/api/app/views/mno_enterprise/jpi/v1/marketplace/show.json.jbuilder
+++ b/api/app/views/mno_enterprise/jpi/v1/marketplace/show.json.jbuilder
@@ -1,3 +1,3 @@
json.app do
json.partial! 'app', app: @app
-end
\ No newline at end of file
+end
diff --git a/api/config/routes.rb b/api/config/routes.rb
index 02ea31a24..24f299a92 100644
--- a/api/config/routes.rb
+++ b/api/config/routes.rb
@@ -91,7 +91,11 @@
#============================================================
namespace :jpi do
namespace :v1 do
- resources :marketplace, only: [:index, :show]
+ resources :marketplace, only: [:index, :show] do
+ member do
+ resources :app_reviews, only: [:index, :create]
+ end
+ end
resource :current_user, only: [:show, :update] do
put :update_password
put :register_developer
@@ -150,6 +154,7 @@
namespace :admin, defaults: {format: 'json'} do
resources :audit_events, only: [:index]
resources :app_instances, only: [:destroy], shallow: true
+ resources :app_reviews, only: [:index, :show, :update]
resources :users, only: [:index, :show, :destroy, :update, :create] do
collection do
get :count
diff --git a/api/spec/controllers/mno_enterprise/jpi/v1/admin/app_reviews_controller_spec.rb b/api/spec/controllers/mno_enterprise/jpi/v1/admin/app_reviews_controller_spec.rb
new file mode 100644
index 000000000..c26cef774
--- /dev/null
+++ b/api/spec/controllers/mno_enterprise/jpi/v1/admin/app_reviews_controller_spec.rb
@@ -0,0 +1,102 @@
+require 'rails_helper'
+
+module MnoEnterprise
+ include MnoEnterprise::TestingSupport::SharedExamples::JpiV1Admin
+
+ describe Jpi::V1::Admin::AppReviewsController, type: :controller do
+ render_views
+ routes { MnoEnterprise::Engine.routes }
+ before { request.env['HTTP_ACCEPT'] = 'application/json' }
+ let(:user) { build(:user, :admin, :with_organizations) }
+ let(:app_review) { build(:app_review, user: user) }
+ before do
+ api_stub_for(get: '/app_reviews', response: from_api([app_review]))
+ api_stub_for(get: "/app_reviews/#{app_review.id}", response: from_api(app_review))
+ api_stub_for(get: "/users/#{user.id}", response: from_api(user))
+ sign_in user
+ end
+
+ def partial_hash_for_app_review(app_review)
+ {
+ 'id' => app_review.id,
+ 'rating' => app_review.rating,
+ 'description' => app_review.description,
+ 'status' => app_review.status,
+ 'app_id' => app_review.app_id,
+ 'app_name' => app_review.app_name,
+ 'user_id' => app_review.user_id,
+ 'user_name' => app_review.user_name,
+ 'organization_id' => app_review.organization_id,
+ 'organization_name' => app_review.organization_name,
+ 'created_at' => app_review.created_at,
+ 'updated_at' => app_review.updated_at,
+ }
+ end
+
+ def hash_for_app_review(app_review)
+ {
+ 'app_review' => partial_hash_for_app_review(app_review)
+ }
+ end
+
+ def hash_for_app_reviews(app_reviews)
+ {
+ 'app_reviews' => app_reviews.map { |o| partial_hash_for_app_review(o) }
+ }
+ end
+
+
+ describe '#index' do
+ subject { get :index }
+
+ it_behaves_like "a jpi v1 admin action"
+
+ context 'success' do
+ before { subject }
+
+ it 'returns a list of app_review' do
+ expect(response).to be_success
+ expect(JSON.parse(response.body)).to eq(JSON.parse(hash_for_app_reviews([app_review]).to_json))
+ end
+ end
+ end
+
+ describe 'GET #show' do
+ subject { get :show, id: app_review.id }
+
+ it_behaves_like "a jpi v1 admin action"
+
+ context 'success' do
+ before { subject }
+
+ it 'returns a complete description of the app_review' do
+ expect(response).to be_success
+ expect(JSON.parse(response.body)).to eq(JSON.parse(hash_for_app_review(app_review).to_json))
+ end
+ end
+ end
+
+
+ describe 'PUT #update' do
+ subject { put :update, id: app_review.id, app_review: {status: 'rejected'} }
+
+ before do
+ sign_in user
+ api_stub_for(put: "/app_reviews/#{app_review.id}", response: -> { app_review.status = 'rejected'; from_api(app_review) })
+ end
+
+ it_behaves_like "a jpi v1 admin action"
+
+ context 'success' do
+ before { subject }
+
+ it { expect(response).to be_success }
+
+ # Test that the app_review is updated by testing the api endpoint was called
+ it { expect(app_review.status).to eq('rejected') }
+ end
+ end
+
+
+ end
+end
diff --git a/api/spec/controllers/mno_enterprise/jpi/v1/app_reviews_controller_spec.rb b/api/spec/controllers/mno_enterprise/jpi/v1/app_reviews_controller_spec.rb
new file mode 100644
index 000000000..2db7fbea6
--- /dev/null
+++ b/api/spec/controllers/mno_enterprise/jpi/v1/app_reviews_controller_spec.rb
@@ -0,0 +1,75 @@
+require 'rails_helper'
+
+module MnoEnterprise
+ describe Jpi::V1::AppReviewsController, type: :controller do
+ include MnoEnterprise::TestingSupport::JpiV1TestHelper
+ render_views
+ routes { MnoEnterprise::Engine.routes }
+ before { request.env["HTTP_ACCEPT"] = 'application/json' }
+
+
+ #===============================================
+ # Assignments
+ #===============================================
+ let(:user) { build(:user) }
+ before { api_stub_for(get: "/users/#{user.id}", response: from_api(user)) }
+ before { sign_in user }
+
+ let(:app) { build(:app) }
+ let(:app_review) { build(:app_review) }
+ let(:expected_hash_for_review) do
+ attrs = %w(id rating description status user_id user_name organization_id organization_name app_id app_name)
+ app_review.attributes.slice(*attrs).merge({'created_at' => app_review.created_at.as_json, 'updated_at' => app_review.updated_at.as_json})
+ end
+ let(:expected_hash_for_reviews) do
+ {
+ 'app_reviews' => [expected_hash_for_review],
+ # 'metadata' => {'pagination' => {'count' => 1}}
+ }
+ end
+
+ before do
+ api_stub_for(get: "/apps/#{app.id}", response: from_api(app))
+ end
+
+ describe 'GET #index' do
+
+ before do
+ api_stub_for(get: "/app_reviews?filter[reviewable_id]=#{app.id}", response: from_api([app_review]))
+ end
+
+ subject { get :index, id: app.id }
+
+ it_behaves_like "jpi v1 protected action"
+
+ it_behaves_like "a paginated action"
+
+ it 'renders the list of reviews' do
+ subject
+ expect(JSON.parse(response.body)).to eq(expected_hash_for_reviews)
+ end
+ end
+
+ describe 'POST #create', focus: true do
+ let(:params) { {organization_id: 1, description: 'A Review', rating: 5, foo: 'bar'} }
+ let(:app_review) { build(:app_review) }
+
+ before do
+ api_stub_for(post: "/app_reviews", response: from_api(app_review))
+ api_stub_for(get: "/app_reviews/#{app_review.id}", response: from_api(app_review))
+ end
+
+ subject { post :create, id: app.id, app_review: params }
+
+ it_behaves_like "jpi v1 protected action"
+
+ it 'renders the new review' do
+ expect(JSON.parse(subject.body)).to include('app_review' => expected_hash_for_review)
+ end
+
+ it 'renders the new average rating' do
+ expect(JSON.parse(subject.body)).to include('average_rating' => app.average_rating)
+ end
+ end
+ end
+end
diff --git a/api/spec/controllers/mno_enterprise/jpi/v1/marketplace_controller_spec.rb b/api/spec/controllers/mno_enterprise/jpi/v1/marketplace_controller_spec.rb
index f0e91efb4..5e2a58990 100644
--- a/api/spec/controllers/mno_enterprise/jpi/v1/marketplace_controller_spec.rb
+++ b/api/spec/controllers/mno_enterprise/jpi/v1/marketplace_controller_spec.rb
@@ -37,7 +37,7 @@ def partial_hash_for_app(app)
'rank' => app.rank,
'multi_instantiable' => app.multi_instantiable,
'subcategories' => app.subcategories,
-
+ 'average_rating' => app.average_rating,
}
end
@@ -73,10 +73,7 @@ def hash_for_apps(apps)
)
end
- it 'is successful' do
- subject
- expect(response).to be_success
- end
+ it { is_expected.to be_success }
it 'returns the right response' do
subject
@@ -90,10 +87,7 @@ def hash_for_apps(apps)
api_stub_for(get: '/apps', response: from_api([app]))
end
- it 'is successful' do
- subject
- expect(response).to be_success
- end
+ it { is_expected.to be_success }
it 'returns the right response' do
subject
@@ -106,10 +100,7 @@ def hash_for_apps(apps)
before { api_stub_for(get: "/apps/#{app.id}", response: from_api(app)) }
subject { get :show, id: app.id }
- it 'is successful' do
- subject
- expect(response).to be_success
- end
+ it { is_expected.to be_success }
it 'returns the right response' do
subject
@@ -129,10 +120,7 @@ def hash_for_apps(apps)
api_stub_for(get: '/apps', response: from_api([app1,app2]))
end
- it 'is successful' do
- subject
- expect(response).to be_success
- end
+ it { is_expected.to be_success }
it 'returns the right response' do
subject
diff --git a/api/spec/routing/mno_enterprise/jpi/v1/admin/app_reviews_controller_routing_spec.rb b/api/spec/routing/mno_enterprise/jpi/v1/admin/app_reviews_controller_routing_spec.rb
new file mode 100644
index 000000000..afe060233
--- /dev/null
+++ b/api/spec/routing/mno_enterprise/jpi/v1/admin/app_reviews_controller_routing_spec.rb
@@ -0,0 +1,19 @@
+require 'rails_helper'
+
+module MnoEnterprise
+ RSpec.describe Jpi::V1::Admin::UsersController, type: :routing do
+ routes { MnoEnterprise::Engine.routes }
+
+ it 'routes to #index' do
+ expect(get('/jpi/v1/admin/app_reviews')).to route_to('mno_enterprise/jpi/v1/admin/app_reviews#index', format: 'json')
+ end
+
+ it 'routes to #show' do
+ expect(get('/jpi/v1/admin/app_reviews/1')).to route_to('mno_enterprise/jpi/v1/admin/app_reviews#show', format: 'json', id: '1')
+ end
+
+ it 'routes to #update' do
+ expect(put('/jpi/v1/admin/app_reviews/1')).to route_to('mno_enterprise/jpi/v1/admin/app_reviews#update', id: '1', format: 'json')
+ end
+ end
+end
diff --git a/api/spec/routing/mno_enterprise/jpi/v1/app_reviews_controller_routing_spec.rb b/api/spec/routing/mno_enterprise/jpi/v1/app_reviews_controller_routing_spec.rb
new file mode 100644
index 000000000..e8b132939
--- /dev/null
+++ b/api/spec/routing/mno_enterprise/jpi/v1/app_reviews_controller_routing_spec.rb
@@ -0,0 +1,15 @@
+require 'rails_helper'
+
+module MnoEnterprise
+ RSpec.describe Jpi::V1::AppReviewsController, type: :routing do
+ routes { MnoEnterprise::Engine.routes }
+
+ it 'routes to #index' do
+ expect(get('/jpi/v1/marketplace/1/app_reviews')).to route_to("mno_enterprise/jpi/v1/app_reviews#index", id: '1')
+ end
+ it 'routes to #create' do
+ expect(post('/jpi/v1/marketplace/1/app_reviews')).to route_to("mno_enterprise/jpi/v1/app_reviews#create", id: '1')
+ end
+ end
+end
+
diff --git a/api/spec/routing/mno_enterprise/jpi/v1/marketplace_controller_routing_spec.rb b/api/spec/routing/mno_enterprise/jpi/v1/marketplace_controller_routing_spec.rb
index 5f264a305..ae3c4e8f0 100644
--- a/api/spec/routing/mno_enterprise/jpi/v1/marketplace_controller_routing_spec.rb
+++ b/api/spec/routing/mno_enterprise/jpi/v1/marketplace_controller_routing_spec.rb
@@ -3,11 +3,11 @@
module MnoEnterprise
RSpec.describe Jpi::V1::MarketplaceController, type: :routing do
routes { MnoEnterprise::Engine.routes }
-
+
it 'routes to #index' do
expect(get('/jpi/v1/marketplace')).to route_to("mno_enterprise/jpi/v1/marketplace#index")
end
-
+
it 'routes to #show' do
expect(get('/jpi/v1/marketplace/1')).to route_to("mno_enterprise/jpi/v1/marketplace#show", id: '1')
end
diff --git a/core/app/models/mno_enterprise/app.rb b/core/app/models/mno_enterprise/app.rb
index e8e73fb12..163683903 100644
--- a/core/app/models/mno_enterprise/app.rb
+++ b/core/app/models/mno_enterprise/app.rb
@@ -31,8 +31,14 @@ class App < BaseResource
scope :cloud, -> { where(stack: 'cloud') }
attributes :id, :uid, :nid, :name, :description, :tiny_description, :created_at, :updated_at, :logo, :website, :slug,
- :categories, :key_benefits, :key_features, :testimonials, :worldwide_usage, :tiny_description,
- :popup_description, :stack, :terms_url, :pictures, :tags, :api_key, :metadata_url, :metadata, :details, :rank, :multi_instantiable, :subcategories
+ :categories, :key_benefits, :key_features, :testimonials, :worldwide_usage, :tiny_description,
+ :popup_description, :stack, :terms_url, :pictures, :tags, :api_key, :metadata_url, :metadata, :details, :rank, :multi_instantiable, :subcategories, :reviews, :average_rating
+
+
+ #================================
+ # Associations
+ #================================
+ has_many :reviews, class_name: 'AppReview'
# Return the list of available categories
def self.categories(list = nil)
diff --git a/core/app/models/mno_enterprise/app_review.rb b/core/app/models/mno_enterprise/app_review.rb
new file mode 100644
index 000000000..6a76a4d81
--- /dev/null
+++ b/core/app/models/mno_enterprise/app_review.rb
@@ -0,0 +1,7 @@
+module MnoEnterprise
+ class AppReview < BaseResource
+ attributes :id, :rating, :description, :created_at, :updated_at, :app_id, :user_id, :organization_id, :status
+
+ scope :approved, -> { where(status: 'approved') }
+ end
+end
diff --git a/core/config/locales/templates/dashboard/marketplace/en.yml b/core/config/locales/templates/dashboard/marketplace/en.yml
index d8a1733f6..14996a7e2 100644
--- a/core/config/locales/templates/dashboard/marketplace/en.yml
+++ b/core/config/locales/templates/dashboard/marketplace/en.yml
@@ -20,6 +20,19 @@ en:
success_notification_title: "{{name}} has been added to your account"
success_launch_notification_body: "To start using {{name}}, click on the {{name}} icon then click on \"Launch\"."
success_connect_notification_body: "To start using {{name}}, click on the {{name}} icon then click on \"Connect\"."
+ no_reviews: "No reviews on"
+ write_review: "Write a review"
+ number_of_reviews: "Reviews per page:"
+ success_toastr: "Your review has been taken into account!"
+ error_toastr: "An error occurred while saving your review."
+ from: "from"
+ "on": "on"
+ just_now: "Just Now"
+ company_feedback: "Company feedback"
+ review: "Review"
+ tell_others: "Tell others what you think about this application (optional)"
+ cancel: "Cancel"
+ submit: "Submit"
app_selection:
next: "Next"
diff --git a/core/lib/generators/mno_enterprise/install/templates/config/settings.yml b/core/lib/generators/mno_enterprise/install/templates/config/settings.yml
index e53eb7aec..a472cb13c 100644
--- a/core/lib/generators/mno_enterprise/install/templates/config/settings.yml
+++ b/core/lib/generators/mno_enterprise/install/templates/config/settings.yml
@@ -7,9 +7,20 @@ mno:
paths:
root: /api/mnoe/v1
frontend_host:
+
+#===============================================
+# Feature Flags
+#===============================================
+
+# Display App Pricing on Marketplace
pricing:
enabled: false
+# Enable the App Dock
dock:
enabled: true
+# Display the Developer section on "My Account"
developer:
enabled: false
+# Enable Reviews in the marketplace
+reviews:
+ enabled: false
diff --git a/core/lib/mno_enterprise/testing_support/factories/app_review.rb b/core/lib/mno_enterprise/testing_support/factories/app_review.rb
new file mode 100644
index 000000000..b30b23756
--- /dev/null
+++ b/core/lib/mno_enterprise/testing_support/factories/app_review.rb
@@ -0,0 +1,23 @@
+# Read about factories at https://github.com/thoughtbot/factory_girl
+
+FactoryGirl.define do
+ factory :mno_enterprise_app_review, :class => 'AppReview' do
+
+ factory :app_review, class: MnoEnterprise::AppReview do
+ sequence(:id)
+ description 'Some Description'
+ status 'approved'
+ rating 3
+ app_id 'app-id'
+ app_name 'the app'
+ user_id 'usr-11'
+ user_name 'Jean Bon'
+ organization_id 'org-11'
+ organization_name 'Organization 11'
+ created_at 3.days.ago
+ updated_at 1.hour.ago
+ # Properly build the resource with Her
+ initialize_with { new(attributes).tap { |e| e.clear_attribute_changes! } }
+ end
+ end
+end
diff --git a/core/lib/mno_enterprise/testing_support/factories/apps.rb b/core/lib/mno_enterprise/testing_support/factories/apps.rb
index f1baaa28a..36f7e7e10 100644
--- a/core/lib/mno_enterprise/testing_support/factories/apps.rb
+++ b/core/lib/mno_enterprise/testing_support/factories/apps.rb
@@ -5,7 +5,7 @@
sequence(:id) { |n| n }
sequence(:name) { |n| "TestApp#{n}" }
nid { name.parameterize }
-
+
description "This is a description"
created_at 1.day.ago
updated_at 2.hours.ago
@@ -14,30 +14,31 @@
slug { "#{id}-myapp" }
categories ["CRM"]
tags ['Foo', 'Bar']
- key_benefits ['Super','Hyper','Good']
- key_features ['Super','Hyper','Good']
- testimonials [{text:'Bla', company:'Doe Pty Ltd', author: 'John'}]
+ key_benefits ['Super', 'Hyper', 'Good']
+ key_features ['Super', 'Hyper', 'Good']
+ testimonials [{text: 'Bla', company: 'Doe Pty Ltd', author: 'John'}]
worldwide_usage 120000
tiny_description "A great app"
stack 'cube'
terms_url "http://opensource.org/licenses/MIT"
appinfo { {} }
+ average_rating 1
sequence(:rank) { |n| n }
- pricing_plans {{
- 'default' =>[{name: 'Monthly Plan', price: '20.0', currency: 'AUD', factor: '/month'}]
- }}
+ pricing_plans { {
+ 'default' => [{name: 'Monthly Plan', price: '20.0', currency: 'AUD', factor: '/month'}]
+ } }
trait :cloud do
stack 'cloud'
end
-
+
trait :connector do
stack 'connector'
end
-
+
factory :cloud_app, traits: [:cloud]
factory :connector_app, traits: [:connector]
-
+
# Properly build the resource with Her
initialize_with { new(attributes).tap { |e| e.clear_attribute_changes! } }
end
diff --git a/core/lib/mno_enterprise/testing_support/jpi_v1_test_helper.rb b/core/lib/mno_enterprise/testing_support/jpi_v1_test_helper.rb
index 74418a096..3bbcfe2b8 100644
--- a/core/lib/mno_enterprise/testing_support/jpi_v1_test_helper.rb
+++ b/core/lib/mno_enterprise/testing_support/jpi_v1_test_helper.rb
@@ -79,4 +79,10 @@ module MnoEnterprise::TestingSupport::JpiV1TestHelper
end
end
+ shared_examples_for "a paginated action" do
+ it 'adds the pagination metadata' do
+ subject
+ expect(response.headers['X-Total-Count']).to be_a(Fixnum)
+ end
+ end
end
diff --git a/frontend-admin/src/app/components/mnoe-api/admin/reviews.svc.coffee b/frontend-admin/src/app/components/mnoe-api/admin/reviews.svc.coffee
new file mode 100644
index 000000000..e0158f9b6
--- /dev/null
+++ b/frontend-admin/src/app/components/mnoe-api/admin/reviews.svc.coffee
@@ -0,0 +1,27 @@
+# Service for managing the comments and reviews.
+@App.service 'MnoeReviews', (MnoeAdminApiSvc) ->
+ _self = @
+
+ # GET List /mnoe/jpi/v1/admin/app_reviews
+ @list = () ->
+ MnoeAdminApiSvc.all('app_reviews').getList().then(
+ (response) ->
+ response
+ (error) ->
+ # Display an error
+ $log.error('Error while fetching reviews', error)
+ toastr.error('An error occured while fetching the reviews.')
+ )
+
+ # UPDATE /mnoe/jpi/v1/admin/app_reviews/1
+ @updateRating = (review) ->
+ promise = MnoeAdminApiSvc.one('app_reviews', review.id).patch({status: review.status}).then(
+ (response) ->
+ response
+ (error) ->
+ # Display an error
+ $log.error('Error while updating review', error)
+ toastr.error('An error occured while updating the review.')
+ )
+
+ return @
diff --git a/frontend-admin/src/app/components/mnoe-reviews-list/mnoe-reviews-list.coffee b/frontend-admin/src/app/components/mnoe-reviews-list/mnoe-reviews-list.coffee
new file mode 100644
index 000000000..f8448cb11
--- /dev/null
+++ b/frontend-admin/src/app/components/mnoe-reviews-list/mnoe-reviews-list.coffee
@@ -0,0 +1,27 @@
+@App.directive('mnoeReviewsList', ($filter, $log, MnoeReviews) ->
+ restric:'E'
+ scope: {
+ }
+ templateUrl:'app/components/mnoe-reviews-list/mnoe-reviews-list.html'
+ link: (scope) ->
+
+ scope.editmode = []
+ scope.listOfReviews = []
+ scope.statuses = ['approved', 'rejected']
+
+ fetchReviews = () ->
+ return MnoeReviews.list().then(
+ (response) ->
+ scope.listOfReviews = response.data
+ )
+
+ scope.update = (review) ->
+ MnoeReviews.updateRating(review).then(
+ (response) ->
+ # Remove the edit mode for this review
+ delete scope.editmode[review.id]
+ )
+
+ fetchReviews()
+ return
+)
diff --git a/frontend-admin/src/app/components/mnoe-reviews-list/mnoe-reviews-list.html b/frontend-admin/src/app/components/mnoe-reviews-list/mnoe-reviews-list.html
new file mode 100644
index 000000000..ed27f3fcb
--- /dev/null
+++ b/frontend-admin/src/app/components/mnoe-reviews-list/mnoe-reviews-list.html
@@ -0,0 +1,60 @@
+