diff --git a/.gitignore b/.gitignore
index edaed0ceb..a4b586cd6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -32,3 +32,5 @@
.DS_Store
.vagrant
+
+/plugins/*
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js.erb
similarity index 97%
rename from app/assets/javascripts/application.js
rename to app/assets/javascripts/application.js.erb
index c9f57b7f9..e9a58fa5d 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js.erb
@@ -72,3 +72,7 @@
//= require_tree ./services
//= require_tree ./directives
//= require_tree ./filters
+
+<%
+PluginRegistry.javascripts.each { |js| require_asset(js) }
+%>
diff --git a/app/assets/javascripts/controllers/main_nav.coffee.erb b/app/assets/javascripts/controllers/main_nav.coffee.erb
index 96b1c5775..8b9a49217 100644
--- a/app/assets/javascripts/controllers/main_nav.coffee.erb
+++ b/app/assets/javascripts/controllers/main_nav.coffee.erb
@@ -44,7 +44,8 @@ Application.Controllers.controller "MainNavController", ["$scope", "$location",
})
- $scope.adminNavLinks = [
+ Fablab.adminNavLinks = Fablab.adminNavLinks || []
+ Fablab.adminNavLinks = [
{
state: 'app.admin.trainings'
linkText: 'trainings_monitoring'
@@ -95,5 +96,7 @@ Application.Controllers.controller "MainNavController", ["$scope", "$location",
linkText: 'customization'
linkIcon: 'gear'
}
- ]
+ ].concat(Fablab.adminNavLinks)
+
+ $scope.adminNavLinks = Fablab.adminNavLinks
]
diff --git a/app/assets/javascripts/controllers/members.coffee b/app/assets/javascripts/controllers/members.coffee
index 6261c15a1..440cf5e43 100644
--- a/app/assets/javascripts/controllers/members.coffee
+++ b/app/assets/javascripts/controllers/members.coffee
@@ -261,7 +261,7 @@ Application.Controllers.controller "EditProfileController", ["$scope", "$rootSco
Application.Controllers.controller "ShowProfileController", ["$scope", 'memberPromise', 'SocialNetworks', ($scope, memberPromise, SocialNetworks) ->
## Selected user's informations
- $scope.user = memberPromise
+ $scope.user = memberPromise # DEPENDENCY WITH NAVINUM GAMIFICATION PLUGIN !!!!
## List of social networks associated with this user and toggle 'show all' state
$scope.social =
diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss.erb
similarity index 86%
rename from app/assets/stylesheets/application.scss
rename to app/assets/stylesheets/application.scss.erb
index bb4619d2b..2ae151239 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss.erb
@@ -34,3 +34,8 @@
@import "modules/invoice";
@import "app.responsive";
+
+<% PluginRegistry.stylesheets.each do |stylesheet| %>
+ <% basename = File.basename(stylesheet,'.scss') %>
+ <%= "@import '#{basename}';" %>
+<% end %>
diff --git a/app/assets/templates/shared/publicProfile.html.erb b/app/assets/templates/shared/publicProfile.html.erb
index 28a8b938a..51773df6a 100644
--- a/app/assets/templates/shared/publicProfile.html.erb
+++ b/app/assets/templates/shared/publicProfile.html.erb
@@ -37,6 +37,7 @@
+ <%= PluginRegistry.insert_code('html.user.profile') %>
@@ -126,4 +127,4 @@
-
\ No newline at end of file
+
diff --git a/app/views/api/members/show.json.jbuilder b/app/views/api/members/show.json.jbuilder
index 5c23588dd..bdc715b02 100644
--- a/app/views/api/members/show.json.jbuilder
+++ b/app/views/api/members/show.json.jbuilder
@@ -1,4 +1,4 @@
-json.extract! @member, :id, :username, :email, :group_id, :slug, :invoicing_disabled, :is_allow_contact
+json.extract! @member, :id, :uid, :username, :email, :group_id, :slug, :invoicing_disabled, :is_allow_contact
json.role @member.roles.first.name
json.name @member.profile.full_name
json.need_completion @member.need_completion?
diff --git a/config/application.rb b/config/application.rb
index a48a2d29e..e18661a56 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -13,12 +13,14 @@ require "rails/all"
require 'elasticsearch/rails/instrumentation'
require 'elasticsearch/persistence/model'
+
# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)
module Fablab
class Application < Rails::Application
+ require 'fab_manager'
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded.
@@ -62,5 +64,20 @@ module Fablab
config.web_console.whitelisted_ips << '10.0.2.2' #vagrant
end
+ # enable the app to find locales in plugins locales directory
+ config.i18n.load_path += Dir["#{Rails.root}/plugins/*/config/locales/*.yml"]
+
+ # enable the app to find views in plugins views directory
+ Dir["#{Rails.root}/plugins/*/views"].each do |path|
+ Rails.application.config.paths['app/views'] << path
+ end
+
+ FabManager.activate_plugins!
+
+ config.after_initialize do
+ if plugins = FabManager.plugins
+ plugins.each { |plugin| plugin.notify_after_initialize }
+ end
+ end
end
end
diff --git a/config/initializers/sidekiq.rb b/config/initializers/sidekiq.rb
index f27f1b87d..180690249 100644
--- a/config/initializers/sidekiq.rb
+++ b/config/initializers/sidekiq.rb
@@ -14,7 +14,8 @@ Sidekiq.configure_server do |config|
schedule_file = "config/schedule.yml"
if File.exists?(schedule_file)
- Sidekiq::Cron::Job.load_from_hash YAML.load_file(schedule_file)
+ rendered_schedule_file = ERB.new(File.read(schedule_file)).result
+ Sidekiq::Cron::Job.load_from_hash YAML.load(rendered_schedule_file)
end
end
diff --git a/config/schedule.yml b/config/schedule.yml
index 09e819987..fdc5438fe 100644
--- a/config/schedule.yml
+++ b/config/schedule.yml
@@ -14,3 +14,5 @@ generate_statistic:
cron: "0 1 * * *"
class: "StatisticWorker"
queue: default
+
+<%= PluginRegistry.insert_code('yml.schedule') %>
diff --git a/config/secrets.yml b/config/secrets.yml
index df471202e..4425cc5fc 100644
--- a/config/secrets.yml
+++ b/config/secrets.yml
@@ -31,6 +31,8 @@ development:
openlab_app_secret: <%= ENV["OPENLAB_APP_SECRET"] %>
openlab_app_id: <%= ENV["OPENLAB_APP_ID"] %>
openlab_base_uri: <%= ENV["OPENLAB_BASE_URI"] %>
+ navinum_api_login: <%= ENV["NAVINUM_API_LOGIN"] %>
+ navinum_api_password: <%= ENV["NAVINUM_API_PASSWORD"] %>
test:
secret_key_base: 83daf5e7b80d990f037407bab78dff9904aaf3c195a50f84fa8695a22287e707dfbd9524b403b1dcf116ae1d8c06844c3d7ed942564e5b46be6ae3ead93a9d30
@@ -53,6 +55,8 @@ test:
openlab_app_secret:
openlab_app_id:
openlab_base_uri:
+ navinum_api_login:
+ navinum_api_password:
staging:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
@@ -82,6 +86,8 @@ staging:
openlab_app_secret: <%= ENV["OPENLAB_APP_SECRET"] %>
openlab_app_id: <%= ENV["OPENLAB_APP_ID"] %>
openlab_base_uri: <%= ENV["OPENLAB_BASE_URI"] %>
+ navinum_api_login: <%= ENV["NAVINUM_API_LOGIN"] %>
+ navinum_api_password: <%= ENV["NAVINUM_API_PASSWORD"] %>
# Do not keep production secrets in the repository,
# instead read values from the environment.
@@ -114,3 +120,5 @@ production:
openlab_app_id: <%= ENV["OPENLAB_APP_ID"] %>
openlab_base_uri: <%= ENV["OPENLAB_BASE_URI"] %>
google_analytics_id: <%= ENV["GA_ID"] %>
+ navinum_api_login: <%= ENV["NAVINUM_API_LOGIN"] %>
+ navinum_api_password: <%= ENV["NAVINUM_API_PASSWORD"] %>
diff --git a/db/schema.rb b/db/schema.rb
index 70830f169..470636d5b 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20160613093842) do
+ActiveRecord::Schema.define(version: 20160526102307) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -269,6 +269,24 @@ ActiveRecord::Schema.define(version: 20160613093842) do
add_index "offer_days", ["subscription_id"], name: "index_offer_days_on_subscription_id", using: :btree
+ create_table "open_api_calls_count_tracings", force: :cascade do |t|
+ t.integer "open_api_client_id"
+ t.integer "calls_count", null: false
+ t.datetime "at", null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ end
+
+ add_index "open_api_calls_count_tracings", ["open_api_client_id"], name: "index_open_api_calls_count_tracings_on_open_api_client_id", using: :btree
+
+ create_table "open_api_clients", force: :cascade do |t|
+ t.string "name"
+ t.integer "calls_count", default: 0
+ t.string "token"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ end
+
create_table "plans", force: :cascade do |t|
t.string "name", limit: 255
t.integer "amount"
@@ -368,7 +386,7 @@ ActiveRecord::Schema.define(version: 20160613093842) do
t.datetime "published_at"
end
- add_index "projects", ["slug"], name: "index_projects_on_slug", unique: true, using: :btree
+ add_index "projects", ["slug"], name: "index_projects_on_slug", using: :btree
create_table "projects_components", force: :cascade do |t|
t.integer "project_id"
@@ -661,6 +679,7 @@ ActiveRecord::Schema.define(version: 20160613093842) do
add_foreign_key "availability_tags", "availabilities"
add_foreign_key "availability_tags", "tags"
add_foreign_key "o_auth2_mappings", "o_auth2_providers"
+ add_foreign_key "open_api_calls_count_tracings", "open_api_clients"
add_foreign_key "prices", "groups"
add_foreign_key "prices", "plans"
add_foreign_key "user_tags", "tags"
diff --git a/docker/env.example b/docker/env.example
index c4af63ab9..f81ef266d 100644
--- a/docker/env.example
+++ b/docker/env.example
@@ -47,3 +47,7 @@ UIB_DATE_FORMAT=dd/MM/yyyy
OPENLAB_APP_SECRET=fSF9jZEWxjHyqjAzzg34jd92
OPENLAB_APP_ID=xLn9CmryyURNNHZiDRYVRXbv
+
+
+NAVINUM_API_LOGIN:
+NAVINUM_API_PASSWORD:
diff --git a/lib/fab_manager.rb b/lib/fab_manager.rb
new file mode 100644
index 000000000..96370fbea
--- /dev/null
+++ b/lib/fab_manager.rb
@@ -0,0 +1,17 @@
+require_dependency 'plugin/instance'
+
+module FabManager
+ class << self
+ attr_reader :plugins
+ end
+
+ def self.activate_plugins!
+ all_plugins = Plugin::Instance.find_all("#{Rails.root}/plugins")
+
+ @plugins = []
+ all_plugins.each do |p|
+ p.activate!
+ @plugins << p
+ end
+ end
+end
diff --git a/lib/plugin/instance.rb b/lib/plugin/instance.rb
new file mode 100644
index 000000000..965e16028
--- /dev/null
+++ b/lib/plugin/instance.rb
@@ -0,0 +1,98 @@
+require 'fileutils'
+require 'plugin_registry'
+
+module Plugin
+ class Instance
+ attr_accessor :path#, :directory
+
+ [:assets, :initializers, :javascripts, :styles].each do |att|
+ class_eval %Q{
+ def #{att}
+ @#{att} ||= []
+ end
+ }
+ end
+
+ def self.find_all(parent_path)
+ [].tap { |plugins|
+ # also follows symlinks - http://stackoverflow.com/q/357754
+ Dir["#{parent_path}/**/*/**/plugin.rb"].sort.each do |path|
+
+ source = File.read(path)
+ # metadata = Plugin::Metadata.parse(source)
+ plugins << self.new(nil, path)
+ end
+ }
+ end
+
+ def initialize(metadata=nil, path=nil)
+ @metadata = metadata
+ @path = path
+ #@directory = path.match(/(.*)\/plugin.rb/)[1]
+ @idx = 0
+ end
+
+ def activate!
+ if @path
+ root_path = "#{File.dirname(@path)}/assets/javascripts"
+ PluginRegistry.register_glob(root_path, 'coffee.erb')
+ end
+
+ self.instance_eval File.read(path), path # execute all code of the plugin main file ! (named plugin.rb)
+
+ register_assets! unless assets.blank?
+
+ Rails.configuration.assets.paths << File.dirname(path) + "/assets"
+
+ Rails.configuration.assets.precompile += [lambda do |filename, path|
+ (Dir["plugins/*/assets/templates"].any? { |p| path.include?(p) }) # useless because already included in application.css/js || (%w(.js).include?(File.extname(filename)) && Dir["plugins/*/assets/javascripts"].any? { |p| path.include?(p) }) || (%w(.css).include?(File.extname(filename)) && Dir["plugins/*/assets/stylesheets"].any? { |p| path.include?(p) })
+ end] #
+
+ Rails.configuration.sass.load_paths += Dir["plugins/*/assets/stylesheets"]
+
+
+ # Automatically include rake tasks
+ Rake.add_rakelib(File.dirname(path) + "/lib/tasks")
+
+ # Automatically include migrations
+ Rails.configuration.paths["db/migrate"] << File.dirname(path) + "/db/migrate"
+ end
+
+ def register_asset(file, opts=nil) # to be used by the plugin !
+ full_path = File.dirname(path) << "/assets/" << file
+ assets << [full_path, opts]
+ end
+
+ def register_code_insertion(key, code)
+ PluginRegistry.code_insertions[key] ||= []
+ PluginRegistry.code_insertions[key] << code
+ end
+
+ def register_css(style) # useless ?
+ styles << style
+ end
+
+ def after_initialize(&block)
+ initializers << block
+ end
+
+ def notify_after_initialize
+ initializers.each do |callback|
+ begin
+ callback.call(self)
+ rescue ActiveRecord::StatementInvalid => e
+ # When running db:migrate for the first time on a new database, plugin initializers might
+ # try to use models. Tolerate it.
+ raise e unless e.message.try(:include?, "PG::UndefinedTable")
+ end
+ end
+ end
+
+ protected
+ def register_assets!
+ assets.each do |asset, opts|
+ PluginRegistry.register_asset(asset, opts)
+ end
+ end
+ end
+end
diff --git a/lib/plugin_registry.rb b/lib/plugin_registry.rb
new file mode 100644
index 000000000..58495ae46
--- /dev/null
+++ b/lib/plugin_registry.rb
@@ -0,0 +1,58 @@
+class PluginRegistry
+ class << self
+ attr_writer :javascripts
+ attr_writer :stylesheets
+
+ def asset_globs
+ @asset_globs ||= Set.new
+ end
+
+ def javascripts
+ @javascripts ||= Set.new
+ end
+
+ def stylesheets
+ @stylesheets ||= Set.new
+ end
+
+ def code_insertions
+ @code_insertions ||= {}
+ end
+ end
+
+ def self.register_glob(root, extension, options=nil)
+ self.asset_globs << [root, extension, options || {}]
+ end
+
+ def self.register_asset(asset, opts=nil)
+ if asset =~ /\.js$|\.js\.erb$|\.js\.es6$|\.coffee$|\.coffee\.erb/
+ # if opts == :admin
+ # self.admin_javascripts << asset
+ # else
+ # if opts == :server_side
+ # self.server_side_javascripts << asset
+ # end
+ self.javascripts << asset
+ # end
+ elsif asset =~ /\.css$|\.scss$/
+ # if opts == :mobile
+ # self.mobile_stylesheets << asset
+ # elsif opts == :desktop
+ # self.desktop_stylesheets << asset
+ # elsif opts == :variables
+ # self.sass_variables << asset
+ # else
+ self.stylesheets << asset
+ # end
+
+ # elsif asset =~ /\.hbs$/
+ # self.handlebars << asset
+ # elsif asset =~ /\.js\.handlebars$/
+ # self.handlebars << asset
+ end
+
+ def self.insert_code(key)
+ self.code_insertions[key].join('\n')
+ end
+ end
+end
diff --git a/plugins/.keep b/plugins/.keep
new file mode 100644
index 000000000..e69de29bb